web-dev-qa-db-fra.com

Ruby on Rails 3 - Recharger le répertoire lib pour chaque requête)

Je crée un nouveau moteur pour une application Rails 3. Comme vous pouvez le deviner, ce moteur se trouve dans le répertoire lib de mon application.

Cependant, j'ai quelques problèmes pour le développer. En effet, je dois redémarrer mon serveur à chaque fois que je change quelque chose dans le moteur.

Y a-t-il un moyen d'éviter cela?

Puis-je forcer Rails à recharger complètement le répertoire lib ou un fichier spécifique et ses exigences pour chaque requête?

Merci de votre aide :)

58
Nicolas Guillaume

TL; DR

  • mettez ceci dans config/application.rb

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

  • supprimer les instructions require pour vos fichiers lib

Aller!


Permettez-moi de vous expliquer en détail.

Je ne sais pas pourquoi cette réponse est acceptée, car elle n'aide pas à recharger le dossier lib à chaque demande . J'ai d'abord pensé que cela fonctionne pour Rails 2, mais la question indique clairement que c'était pour Rails 3 et la date de sortie de 3.0.0 est avant la date de la réponse.

D'autres réponses semblent trop compliquées ou n'apportent pas de véritable solution.

J'ai décidé d'étudier un peu les choses, car cela me dérangeait et j'ai même découvert que les gens avaient une solution pour cela et cela impliquait d'enregistrer des fichiers lib à l'intérieur de app/models en cours de développement, puis le déplacer vers /lib lorsque vous avez terminé. Nous pouvons faire mieux, non?


Ma solution est testée contre:

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

Mettez ceci dans votre config/application.rb:

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

C'est tout! ™

Assurez-vous de le mettre ici car il ne fonctionnera pas si vous le mettez dans config/environments/development.rb, par exemple.

Assurez-vous de supprimer toutes les instructions require pour votre /lib code puisque les instructions require feront également que cette solution ne fonctionnera pas.


Ce code nécessite implicitement votre code, donc si vous effectuez des vérifications d'environnement (qui ne sont pas nécessaires) et au lieu du code ci-dessus, vous décidez d'écrire quelque chose comme ceci:

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

vous devez faire attention aux anciennes instructions require, car elles sont toujours requises sur tous les environnements non destinés au développement, dans ce scénario.

Donc, si vous décidez toujours de faire des vérifications d'environnement, assurez-vous de faire des vérifications inverses pour les instructions require. Sinon, vous serez mordu!

require "beer_creator" unless Rails.env.development?

Vous pourriez penser qu'écrire un paragraphe entier sur quelque chose d'inutile n'est pas nécessaire non plus, mais je pense qu'il est également nécessaire d'avertir les gens de quelque chose qui est nécessaire lorsque vous faites quelque chose d'inutile.

Si vous souhaitez en savoir plus sur ce sujet, consultez ce petit tutoriel .

33
shime

Je n'ai pas pu faire fonctionner ce qui précède pour moi, j'ai donc creusé un peu le code Rails) et j'ai trouvé ceci:

Nouveau fichier: 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

Oui, je sais que c'est dégoûtant mais c'est un hack. Il pourrait y avoir un meilleur moyen de déclencher un rechargement complet, mais cela fonctionne pour moi. Mon cas d'utilisation spécifique était une application Rack montée sur une route Rails donc j'en avais besoin pour la recharger pendant que je travaillais dessus en cours de développement.

Fondamentalement, il vérifie si des fichiers dans/lib ont changé (horodatage modifié) depuis le dernier chargement, puis déclenche un rechargement s'ils changent.

Je pourrais également mentionner que je l'ai dans ma config/application.rb

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

Ce qui juste par défaut s'assure que tout dans mon répertoire lib est chargé.

Ouais!

49
Patrick Hogan

Puisque nous parlons de Rails, la manière la plus simple est de "demander" vos fichiers lib/* .rb en utilisant " require_dependency ". Tant que le contrôleur/assistant/etc (fichiers .rb sous app /) utilise require_dependency au lieu de simplement exiger des travaux de rechargement, sans avoir à faire quoi que ce soit de funky.

Avant de me lancer dans cette voie, la seule solution qui fonctionnait était celle sur hemju.com , mais je ne voulais vraiment pas avoir à pirater l'ApplicationController pour la vitesse de développement.

21
Paul Saladna

Vous devez ajouter

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

à votre classe Application dans config/application.rb

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

13
dishod

Dans Rails 3, voici la sauce secrète pour recharger automatiquement les fichiers lib. Le code ci-dessous est un peu exagéré, par exemple, mais c'est ce que j'ai fait pour le faire fonctionner. Vous pouvez changer le message dans YoYo # gogo et voyez-le à l'écran à chaque chargement de page. Retirez l'initialiseur et il reste le même.

/ config/initializers/lib_reload.rb (nouveau fichier)

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
3
Jesse Wolgamott

Voici ma version inspirée de la réponse de @ pbhogan qui recharge tous les fichiers Ruby dans votre répertoire Rails/lib le cas échéant) de ces fichiers est modifié.

Il coupe également les avertissements pour éviter les messages concernant les constantes déjà initialisées.

Fonctionne à partir de 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
3
jeremiemv

Réponse mise à jour

Je résume toutes mes découvertes sur mon blog, il vaut mieux y regarder:

Ancienne réponse

J'ai aussi cherché une solution pour cela, et (par souci d'exhaustivité et pour orienter les autres dans cette direction) voici ce que j'ai trouvé.

Depuis Rails3.1, les moteurs peuvent facilement être générés via la commande Rails plugin new my_plugin --full. Cela génère le squelette d'un moteur.

--full signifie que le moteur sera "fusionné" directement dans l'application incluse, de sorte que, par exemple, les contrôleurs devraient être directement accessibles comme s'ils étaient définis dans l'application incluse. Cela vous permet par exemple avoir un fichier d'aide dans my_engine/app/helpers/my_helper.rb qui sera fusionné directement dans votre application incluse app/helpers/my_helper.rb helper.

Il y a une autre option --mountable qui crée un espace de noms pour le moteur afin que ses contrôleurs, etc. ne se heurtent jamais à ceux de l'application incluse. Il en résulte par exemple un assistant étant dans my_engine/app/helpers/my_engine/my_helper.rb qui n'entrera pas en collision avec un assistant app/helpers/my_helper.rb dans votre application incluse.

Maintenant la partie la plus intéressante :

Dans le dossier test du moteur généré, il y a un dossier dummy qui contient une application complète Rails! À quoi ça sert?

Lorsque vous développez un moteur, ses fonctionnalités sont censées fonctionner entièrement par elles-mêmes, et il doit également être testé complètement par lui-même. C'est donc la "mauvaise" façon de développer un moteur "dans" une autre application Rails (bien que cela se sente intuitivement souvent correct lors de l'extraction des fonctionnalités existantes d'un Rails dans un moteur), et donc théoriquement, il n'est pas non plus nécessaire de recharger le code d'un moteur à chaque demande vers l'application incluse.

La "bonne" façon semble être la suivante: développer et tester votre moteur, comme s'il s'agissait d'une application complète Rails utilisant l'application dummy! Vous pouvez y faire tout ce que vous pouvez faire dans n'importe quelle application "normale" Rails, par exemple créer des contrôleurs, des modèles, des vues, etc. qui utilisent les fonctionnalités que le moteur devrait fournir. Vous pouvez également normalement démarrer un serveur en utilisant Rails s dans votre test/dummy répertoire et accédez à l'application factice sur localhost:3000, et lors de l'exécution de vos tests, l'application dummy est automatiquement utilisée pour les tests d'intégration. Plutôt sympa! :-)

Vous devez faire attention où mettre vos affaires:

  • Toute fonctionnalité destinée à être utilisée dans une autre application Rails va dans my_engine/app, tandis que toutes les fonctionnalités qui sont uniquement nécessaires pour tester les fonctionnalités du moteur vont dans test/dummy/app.

Ensuite, vous pouvez facilement charger votre moteur dans le Gemfile de votre application principale comme ceci: gem 'my_engine', :path => 'path/to/my_engine' ou le publier sur GitHub en tant que gemme.

(Une chose intéressante (et pour revenir au sujet de ce sujet) est que lorsque je démarre le serveur du mannequin, tous les changements dans le moteur semblent y être reflétés! Il semble donc possible d'inclure un moteur dans a = Rails app sans la mettre en cache ...? Je ne sais pas comment cela se produit.)

Donc, pour résumer: un moteur fournit des fonctionnalités qui peuvent se suffire à lui-même, il devrait donc également être développé et testé par lui-même. Puis, quand il a atteint un état stable, il peut être inclus par n'importe quelle autre application qui a besoin de ses fonctionnalités.

Voici quelques ressources que je trouve utiles:

J'espère que cette réponse vous sera utile. Je suis encore très nouveau dans les moteurs en général, donc s'il y a des informations erronées, dites-le moi et je les corrigerai.

1
Joshua Muheim

Ajouter à application_controller.rb ou votre contrôleur de 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

A travaillé pour moi.

1
Haris Krajina

Assurez-vous également de commenter la ligne suivante dans application.rb (en plus de la solution de @ dishod) et assurez-vous que le nom de votre module est le même que le nom de votre fichier (sinon, Rails = ne pourra pas le trouver)

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

A travaillé pour Rails 3.2.13 pour recharger la lib à l'intérieur de la gemme d'une application:

require_dependency 'the_class'

ET

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

0
rndrfero

notez que dans Rails 3 "load_once_paths" devient "autoload_once_paths".

En outre, il semble qu'il devrait être vide, sauf si vous y mettez explicitement quelque chose.

0
Avram Dorfman