Ruby on Rails 3 – Ricarica la directory lib per ogni richiesta

Sto creando un nuovo motore per un’applicazione rails 3. Come puoi immaginare, questo motore si trova nella directory lib della mia applicazione.

Tuttavia, ho alcuni problemi a svilupparlo. Infatti, ho bisogno di riavviare il mio server ogni volta che cambio qualcosa nel motore.

C’è un modo per evitarlo ?

Posso forzare i binari a ricaricare completamente la directory lib o un file specifico e i suoi requisiti per ogni richiesta?

Grazie per l’aiuto 🙂

TL; DR

  • metti questo in config / application.rb

    config.eager_load_paths += ["#{Rails.root}/lib"]

  • rimuovere require istruzioni per i file lib

Partire!


Lasciatemi spiegare in dettaglio.

Non so perché questa risposta sia accettata, poiché non aiuta a ricaricare la cartella lib su ogni richiesta . Per prima cosa ho pensato che funzioni per Rails 2, ma la domanda afferma chiaramente che era per Rails 3 e la data di rilascio di 3.0.0 è precedente alla data della risposta.

Altre risposte sembrano troppo complicate o non forniscono una soluzione reale.

Ho deciso di indagare un po ‘le cose, perché mi dava fastidio e ho persino scoperto che le persone hanno una soluzione per questo e ciò comporta il salvataggio di file lib all’interno di app/models in fase di sviluppo e il successivo spostamento in /lib volta terminato. Possiamo fare meglio, giusto?


La mia soluzione è testata contro:

  • Rails 3.0.20
  • Rotaie 3.1.12
  • Rotaie 3.2.13
  • Rails 4.0.0.rc1

Metti questo nel tuo config/application.rb :

 # in config/application.rb config.eager_load_paths += ["#{Rails.root}/lib"] 

Questo è tutto! ™

Assicurati di metterlo qui poiché non funzionerà se lo metti in config/environments/development.rb , per esempio.

Assicurati di rimuovere tutte le istruzioni require per il tuo codice /lib poiché le istruzioni require causeranno il malfunzionamento della soluzione.


Questo codice richiede implicitamente il tuo codice, quindi se fai controlli sull’ambiente (che non sono necessari) e invece del codice precedente, decidi di scrivere qualcosa come questo:

 # in config/application.rb config.eager_load_paths += ["#{Rails.root}/lib"] if Rails.env.development? 

dovresti fare attenzione alle vecchie istruzioni require , poiché sono ancora richieste in tutti gli ambienti non di sviluppo, in questo scenario.

Quindi, se decidi di fare controlli ambientali, assicurati di fare controlli inversi per richiedere istruzioni. Altrimenti verrai morso!

 require "beer_creator" unless Rails.env.development? 

Potresti pensare che scrivere interi paragrafi su qualcosa che non è necessario sia anche inutile, ma penso che sia necessario avvertire le persone riguardo a qualcosa che è necessario quando si fa qualcosa di non necessario.

Se vuoi saperne di più su questo argomento, dai un’occhiata a questo piccolo tutorial .

Non sono riuscito a ottenere nulla di quanto sopra per lavorare per me, quindi ho scavato un po ‘nel codice Rails e ho trovato questo:

Nuovo file: config / initializers / reload_lib.rb

 if Rails.env == "development" lib_reloader = ActiveSupport::FileUpdateChecker.new(Dir["lib/**/*"]) do Rails.application.reload_routes! # or do something better here end # For Rails 5.1+ ActiveSupport::Reloader.to_prepare do lib_reloader.execute_if_updated end # For Rails pre-5.1 ActionDispatch::Callbacks.to_prepare do lib_reloader.execute_if_updated end end 

Sì, lo so che è disgustoso ma è un trucco. Potrebbe esserci un modo migliore per triggersre una ricarica completa, ma questo funziona per me. Il mio caso d’uso specifico era un’app Rack montata su un percorso Rails, quindi ne avevo bisogno per ricaricare mentre lavoravo su di esso in fase di sviluppo.

Fondamentalmente quello che fa è controllare se qualche file in / lib è stato modificato (timestamp modificato) dall’ultimo caricato e quindi triggers una ricarica se cambia.

Potrei anche menzionare che ho questo nel mio config / application.rb

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

Il che, per impostazione predefinita, assicura che tutto nella mia directory lib venga caricato.

Yays!

Dato che stiamo parlando di Rails, il modo più semplice è quello di ‘richiedere’ i file lib / * .rb usando ‘ require_dependency ‘. Finché il controller / helper / etc (file .rb sotto app /) usa require_dependency invece di richiedere solo lavori di ricaricamento, senza la necessità di fare qualcosa di funky.

Prima di andare su quella traccia, l’unica soluzione che funzionava era quella su hemju.com , ma non volevo assolutamente hackerare ApplicationController per Dev speed.

Devi aggiungere

 config.autoload_paths += %W(#{config.root}/lib) 

alla tua class Application in config / application.rb

https://rails.lighthouseapp.com/projects/8994/tickets/5218-rails-3-rc-does-not-autoload-from-lib

In RAILS 3, ecco la salsa segreta per ricaricare automaticamente i file lib. Il codice qui sotto è un po ‘eccessivo, per esempio, ma è quello che ho fatto per farlo funzionare. Puoi cambiare il messaggio in YoYo # gogo e vederlo sullo schermo ogni caricamento della pagina. Rimuovi l’inizializzatore e rimane lo stesso.

/config/initializers/lib_reload.rb (nuovo file)

 ActiveSupport::Dependencies.explicitly_unloadable_constants << 'YoYo' ActiveSupport::Dependencies.autoload_once_paths.delete(File.expand_path(File.dirname(__FILE__))+'/lib') 

/lib/yo_yo.rb

 class YoYo def gogo "OH HAI THERE" end end 

/ app / controllers / home_controller

 require 'yo_yo' class HomeController < ApplicationController def index @message = YoYo.new.gogo end end 

Ecco la mia versione ispirata alla risposta di @pbhogan che ricarica tutti i file ruby ​​nella directory rails / lib quando uno di questi file viene modificato.

Mette inoltre a tacere gli avvisi per evitare messaggi relativi a costanti già inizializzate.

Funziona a partire da Rails 3.2.8

 if Rails.env.development? lib_ruby_files = Dir.glob(File.join("lib/**", "*.rb")) lib_reloader ||= ActiveSupport::FileUpdateChecker.new(lib_ruby_files) do lib_ruby_files.each do |lib_file| silence_warnings { require_dependency(lib_file) } end end ActionDispatch::Callbacks.to_prepare do lib_reloader.execute_if_updated end end 

Risposta aggiornata

Riassumo tutte le mie scoperte sul mio blog, è meglio che guardi lì:

Vecchia risposta

Ho cercato anche una soluzione per questo, e (per completezza d’animo e anche per indirizzare gli altri in questa direzione) ecco cosa ho trovato.

A partire da Rails3.1, i motori possono essere facilmente generati tramite il rails plugin new my_plugin --full comando rails plugin new my_plugin --full . Questo genera lo scheletro per un motore.

--full significa che il motore verrà “fuso” direttamente nell’applicazione inclusa, in modo che ad esempio i controllori debbano essere direttamente accessibili come se fossero definiti nell’app inclusa. Ciò ti consente, ad esempio, di avere un file di supporto in my_engine/app/helpers/my_helper.rb che verrà unito direttamente app/helpers/my_helper.rb helper .

C’è un’altra opzione --mountable che crea uno spazio dei nomi per il motore in modo che i suoi controller, ecc. Non --mountable mai in collisione con quelli inclusi dell’applicazione. Ciò si traduce, ad esempio, in un helper che si trova in my_engine/app/helpers/my_engine/my_helper.rb che non entrerà in collisione con app/helpers/my_helper.rb nella tua app inclusa.

Ora la parte più interessante :

All’interno della cartella di test del motore generato, c’è una cartella dummy che contiene un’applicazione Rails completa! Per cosa è?

Quando sviluppi un motore, le sue funzionalità sono pensate per funzionare completamente da sole e dovrebbero essere testate completamente da solo. Quindi è il modo “sbagliato” per sviluppare un motore “all’interno di un’altra app Rails (anche se questo intuitivamente spesso sembrerà giusto quando estrai le funzionalità esistenti da un’app Rails a un motore), quindi in teoria non è nemmeno necessario ricaricare il motore codice con ogni richiesta per l’applicazione inclusa.

Il modo “giusto” sembra essere questo: sviluppare e testare il tuo motore, come se fosse un’app completa di Rails che usa l’app dummy ! Qui puoi fare tutto ciò che puoi fare in qualsiasi app Rails “normale”, ad esempio creare controller, modelli, viste, ecc. Che utilizzano le funzionalità che il motore dovrebbe fornire. In genere, puoi anche avviare un server utilizzando le rails s nella tua directory test/dummy e accedere all’app dummy su localhost:3000 e, quando esegui i test, l’app dummy viene utilizzata automaticamente per i test di integrazione. Piuttosto bella! 🙂

Devi stare attento a dove mettere le tue cose:

  • Qualsiasi funzionalità che deve essere utilizzata all’interno di un’altra app Rails va in my_engine/app , mentre qualsiasi funzionalità necessaria solo per testare la funzionalità del motore va in test/dummy/app .

Successivamente, puoi facilmente caricare il tuo motore nel Gemfile della tua app principale in questo modo: gem 'my_engine', :path => 'path/to/my_engine' o pubblicarlo su GitHub come gem.

(Una cosa interessante (e tornare all’argomento di questo argomento) è che quando avvio il server di dummy, tutte le modifiche nel motore sembrano riflettersi al suo interno! Quindi, in qualche modo, sembra ansible includere un motore all’interno di un Rails app senza nasconderlo …? Non so come ciò accada.)

Quindi, per riassumere: un motore fornisce funzionalità che possono reggersi completamente da solo, quindi dovrebbe anche essere sviluppato e testato da solo. Quindi, quando ha raggiunto uno stato stabile, può essere incluso da qualsiasi altra app che ha bisogno della sua funzionalità.

Ecco alcune risorse che trovo utili:

  • Sviluppo di un RubyGem usando Bundler
  • Motori installabili RailsCast
  • Prenota “Rails 3 in Action”

Spero che questa risposta ti sia utile. Sono ancora molto nuovo ai motori in generale, quindi se ci sono informazioni sbagliate, per favore dimmelo, e lo correggerò.

Aggiungi a application_controller.rb o al tuo controller di base:

  before_filter :dev_reload if Rails.env.eql? 'development' def dev_reload # add lib files here ["rest_client.rb"].each do |lib_file| ActiveSupport::Dependencies.load_file lib_file end end 

Ha funzionato per me

si noti che in Rails 3 “load_once_paths” diventa “autoload_once_paths”.

Inoltre, sembra che dovrebbe essere vuoto a meno che non si inserisca esplicitamente qualcosa in esso.

Inoltre, assicurati di commentare la seguente riga in application.rb (in aggiunta alla soluzione di @ dishod) e assicurati che il nome del tuo modulo sia uguale al nome del tuo file (altrimenti i binari non saranno in grado di trovarlo )

 #Dir.glob("./lib/*.{rb}").each { |file| require file } # require each file from lib directory 

Ha funzionato per Rails 3.2.13 per il ricaricamento di lib all’interno della gem di un’app:

require_dependency ‘the_class’

E

config.autoload_paths + =% W (# {config.root} /../ fantasy / lib)