Il modo migliore per caricare il modulo / classe dalla cartella lib in Rails 3?


273

Dato che l'ultima versione di Rails 3 non carica più automaticamente moduli e classi da lib, quale sarebbe il modo migliore per caricarli?

Da github:

A few changes were done in this commit:

Do not autoload code in *lib* for applications (now you need to explicitly 
require them). This makes an application behave closer to an engine 
(code in lib is still autoloaded for plugins);

Risposte:


251

A partire da Rails 2.3.9 , esiste un'impostazione config/application.rbin cui è possibile specificare le directory che contengono file che si desidera caricare automaticamente.

Da application.rb:

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)

7
Nota la risposta di @grazie anche se stai cercando di caricare automaticamente l'intero sottostruttura di app/lib.
Tom Harrison,

199
# Autoload lib/ folder including all subdirectories
config.autoload_paths += Dir["#{config.root}/lib/**/"]

Fonte: Rails 3 Quicktip: carica automaticamente la directory lib comprese tutte le sottodirectory, evitando il caricamento lento

Tenere presente che i file contenuti nella cartella lib vengono caricati solo all'avvio del server. Se desideri il comfort per ricaricare automaticamente quei file, leggi: Rails 3 Quicktip: ricarica automaticamente le cartelle lib in modalità di sviluppo . Tenere presente che ciò non è previsto per un ambiente di produzione poiché il caricamento permanente rallenta la macchina.


I collegamenti sono morti
Besi,

84

La magia di roba a caricamento automatico

Penso che l'opzione che controlla le cartelle da cui viene eseguito il caricamento automatico sia stata sufficientemente trattata in altre risposte. Tuttavia, nel caso in cui qualcun altro abbia dei problemi caricati anche se i loro percorsi di caricamento automatico sono stati modificati come richiesto, allora questa risposta cerca di spiegare qual è la magia dietro questa cosa di caricamento automatico.

Quindi, quando si tratta di caricare materiale da sottodirectory, c'è un gotcha o una convenzione che dovresti conoscere. A volte la magia di Ruby / Rails (questa volta principalmente Rails) può rendere difficile capire perché sta accadendo qualcosa. Qualsiasi modulo dichiarato nei percorsi di caricamento automatico verrà caricato solo se il nome del modulo corrisponde al nome della directory principale. Quindi nel caso in cui provi a inserire lib/my_stuff/bar.rbqualcosa come:

module Foo
  class Bar
  end
end

Non verrà caricato automaticamente. Poi di nuovo se si rinomina il dir genitore per fooospitare così il modulo nel percorso: lib/foo/bar.rb. Sarà lì per te. Un'altra opzione è quella di nominare il file che si desidera caricare automaticamente dal nome del modulo. Ovviamente ci può essere solo un file con quel nome allora. Nel caso in cui sia necessario dividere le tue cose in molti file, puoi ovviamente usare quel file per richiedere altri file, ma non lo consiglio, perché quando si è in modalità di sviluppo e si modificano quegli altri file, Rails non è in grado di automagicamente ricaricali per te. Ma se vuoi davvero potresti avere un file con il nome del modulo che specifica quindi i file effettivi richiesti per usare il modulo. Quindi potresti avere due file: lib/my_stuff/bar.rbe lib/my_stuff/foo.rbil primo è lo stesso di sopra e il secondo contenente una sola riga:require "bar"e funzionerebbe allo stesso modo.

PS Mi sento in dovere di aggiungere un'altra cosa importante. Di recente, ogni volta che voglio avere qualcosa nella directory lib che deve essere caricato automaticamente, tendo a iniziare a pensare che se questo è qualcosa che sto effettivamente sviluppando specificamente per questo progetto (che di solito è, potrebbe un giorno si trasforma in uno snippet di codice "statico" usato in molti progetti o in un sottomodulo git, ecc. nel qual caso dovrebbe sicuramente trovarsi nella cartella lib) quindi forse il suo posto non è affatto nella cartella lib. Forse dovrebbe essere in una sottocartella sotto la cartella dell'app · Ho la sensazione che questo sia il nuovo modo di fare le rotaie. Ovviamente, la stessa magia è attiva ovunque nei tuoi percorsi di caricamento automatico in cui metti le tue cose, quindi è buono con queste cose. Comunque, questo è solo il mio pensiero sull'argomento. Sei libero di non essere d'accordo. :)


AGGIORNAMENTO: informazioni sul tipo di magia ..

Come ha sottolineato Severin nel suo commento, il nucleo "carica automaticamente un meccanismo del modulo" fa sicuramente parte di Ruby, ma la roba dei percorsi di caricamento automatico non lo è. Non hai bisogno di Rails per farloautoload :Foo, File.join(Rails.root, "lib", "my_stuff", "bar"). E quando proveresti a fare riferimento al modulo Foo per la prima volta, verrà caricato per te. Tuttavia, ciò che fa Rails è che ci dà un modo per provare a caricare roba automagicamente da cartelle registrate e questo è stato implementato in modo tale che deve assumere qualcosa sulle convenzioni di denominazione. Se non fosse stato implementato in quel modo, ogni volta che fai riferimento a qualcosa che non è attualmente caricato dovrebbe passare attraverso tutti i file in tutte le cartelle di caricamento automatico e verificare se qualcuno di essi contiene ciò a cui stavi cercando di fare riferimento. Questo a sua volta vanificherebbe l'idea del caricamento automatico e del caricamento automatico. Tuttavia, con queste convenzioni in atto, è possibile dedurre dal modulo / classe il tentativo di caricare dove potrebbe essere definito e caricarlo.


1
Perché questa magia di Ruby? Ruby fornisce solo la funzione di caricamento automatico del modulo n. Che è possibile utilizzare per comandare un file caricato quando si accede a una costante (non definita) (consultare ruby-doc.org/core-1.9.3/Module.html#method-i-autoload ). La corrispondenza dei nomi dei moduli / classi con le directory / i file è secondo me fatta in Rails / ActiveSupport (ad es. Qui: github.com/rails/rails/blob/… ). Ho sbagliato?
Severin,

Sì, credo che tu abbia ragione. Ero troppo frettoloso per "correggere" la mia risposta originale quando Zabba ha sottolineato il suo "difetto". Vorrei aggiornare un po 'di più la mia risposta per chiarire questo problema.
Timo,

1
Ho passato circa mezz'ora a fare il pasticcio. Avevo bisogno (voluto) di caricare automaticamente i pignoni :: JSRender :: Processor. Il percorso per questo può essere trovato entrando nella console di rotaie e facendo "Sprockets :: JSRender :: Processor" .underscore e smentendo che si tratta di "sprockets / js_render / processor" (con .rb aggiunto) HTH qualcuno.
pedz

Mi hai appena salvato la sanità mentale. ~ profondo sospiro di sollievo ~ grazie mille per la condivisione :)
Brenden,

Grazie per questo commento molto utile. Non ho capito perché alcuni moduli si comportassero come hanno fatto fino a quando non ho letto il tuo commento. Benedizioni su di te!
mjnissim,

41

Avvertenza: se si desidera caricare la "patch scimmia" o "classe aperta" dalla cartella "lib", non utilizzare l' approccio "caricamento automatico" !!!

  • Approccio " config.autoload_paths ": funziona solo se si sta caricando una classe definita solo in UNA posizione. Se una classe è già stata definita da qualche altra parte, non è possibile caricarla di nuovo con questo approccio.

  • Approccio " config / initializer / load_rb_file.rb ": funziona sempre! qualunque sia la classe target è una nuova classe o una "classe aperta" o "patch scimmia" per la classe esistente, funziona sempre!

Per maggiori dettagli, consultare: https://stackoverflow.com/a/6797707/445908


6
Questa è una distinzione fondamentale da capire. Grazie per questo.
Tyler Collier,

28

Molto simile, ma penso che sia un po 'più elegante:

config.autoload_paths += Dir["#{config.root}/lib", "#{config.root}/lib/**/"]

18

Nel mio caso stavo cercando di caricare semplicemente un file direttamente nella directory lib.

All'interno di application.rb ...

require '/lib/this_file.rb' 

non funzionava, nemmeno in console e poi quando ho provato

require './lib/this_file.rb' 

e rails carica il file perfettamente.

Sono ancora piuttosto nobile e non sono sicuro del perché funzioni, ma funziona. Se qualcuno volesse spiegarmelo, lo apprezzerei: DI spero che questo aiuti qualcuno in entrambi i modi.


2
Questo perché ./lib/this_file.rb cerca nella directory corrente (nella console di Rails, quella sarebbe la tua radice di Rails), e /lib/this_file.rb lo cerca come percorso assoluto. Esempio: ./lib/this_file.rb = /var/www/myrailsapp/lib/this_file.rb, /lib/this_file.rb = /lib/this_file.rb
Jason

7

Ho avuto lo stesso problema. Ecco come l'ho risolto. La soluzione carica la directory lib e tutte le sottodirectory (non solo quelle dirette). Ovviamente puoi usarlo per tutte le directory.

# application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]

5
Ciò ha il brutto effetto collaterale del fatto che le convenzioni sulla spaziatura dei nomi di Rails siano totalmente occulte. Se lib / bar / foo.rb che definisce Bar :: Foo appare prima di lib / foo.rb che definisce Foo nella ricerca del caricamento automatico, allora otterrai errori confusi come Expected lib/bar/foo.rb to define constant Foose provassi a caricare lib / foo.rb facendo riferimento a Foo costante.
Jacob,

5

config.autoload_paths non funziona per me. Lo risolvo in altro modo

Ruby on rails 3 non ricarica automaticamente il codice (caricamento automatico) dalla cartella / lib. Lo risolvo mettendo dentroApplicationController

Dir["lib/**/*.rb"].each do |path|
  require_dependency path
end 

4

Se solo alcuni file necessitano dell'accesso ai moduli in lib, aggiungi semplicemente un'istruzione obbligatoria ai file che ne hanno bisogno. Ad esempio, se un modello deve accedere a un modulo, aggiungere:

require 'mymodule'

nella parte superiore del file model.rb.


50
Non dovresti usarlo requireall'interno di un'app rotaie, perché impedisce ActiveSupport::Dependenciesdi [annullare] caricare correttamente quel codice. Invece dovresti usare config.autoload_pathscome la risposta sopra e quindi includere / estendere come richiesto.
ben_h,

13
Grazie @ Mike, stavo per fare quello che hai fatto, è stato bello vedere una spiegazione del perché è male, grazie per non aver rimosso la risposta.
pupeno,

che ne dici di includere 'mymodule' se vuoi solo caricare un modulo?
Mike,

1
@ben_h Non dovresti trovarti requireda nessuna parte in un'app Rails? In un compito rastrello Attualmente sto require-ing e include-ing un modulo che vive in lib/. Non dovrei farlo?
Dennis,

@ben_h La mia ricerca rivela che è comune al requiretuo lib/codice (ad esempio questo post sul blog , questa risposta SO ). Non sono ancora sicuro di tutto. Puoi fornire ulteriori prove dietro la richiesta di non utilizzo require?
Dennis,

2

Scrivi correttamente il nome del file.

Sul serio. Ho combattuto con una classe per un'ora perché la classe era Governance :: ArchitectureBoard e il file era in lib / governance / architecture_baord.rb (trasposto O e A in "board")

Sembra ovvio a posteriori, ma è stato il diavolo a rintracciarlo. Se la classe non è definita nel file in cui Rails si aspetta che sia basata sul munging del nome della classe, semplicemente non la troverà.


2

Come di Rails 5, si consiglia di mettere nella cartella lib nella directory app o invece creare altri spazi nome significativo per la cartella come services, presenters, featuresecc e metterlo sotto la directory app per caricamento automatico dalle rotaie.

Controlla anche questo link di discussione su GitHub .


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.