Rails 5: charger les fichiers lib en production

128

J'ai mis à niveau l'une de mes applications de Rails 4.2.6 vers Rails 5.0.0. Le guide de mise à niveau indique que la fonction de chargement automatique est maintenant désactivée en production par défaut.

Maintenant, j'obtiens toujours une erreur sur mon serveur de production car je charge tous les fichiers lib avec autoload dans le application.rbfichier.

module MyApp
    class Application < Rails::Application
        config.autoload_paths += %W( lib/ )
    end
end

Pour l'instant, j'ai réglé le config.enable_dependency_loadingsur truemais je me demande s'il existe une meilleure solution à cela. Il doit y avoir une raison pour laquelle le chargement automatique est désactivé par défaut en production.

Tobias
la source
chose folle, et les documents vous disent toujours de faire auto_load. J'étais très confus sur ce qui ne va pas dans l'environnement de production pour une nouvelle application. Et depuis que j'ai commencé à apprendre avec Rails 5, je n'ai pas lu le guide de migration. J'espère que j'ai déposé un problème de documentation pour résoudre le problème
akostadinov
1
étonnamment, j'ai deux fichiers dans libdir, un fichier est facilement disponible dans Runtime, mais un autre doit être requis manuellement: D
illusionniste
@Tobias Quelle solution avez-vous trouvée?
geoboy
@geoboy Je groupe le code (comme Validators) dans des dossiers directement dans le répertoire app / car le code y est automatiquement chargé.
Tobias
il est sur le chemin de fichier et définition de la classe est ici ce travail pour moi dans Rails 5.2: Chemin du fichier: app/services/paylinx/paylinx_service.rbdéfinition de classe: module Paylinx class PaylinxService end end. J'ai essayé ces autoload_pathstrucs. ne fonctionne pas pour moi.
NamNamNam

Réponses:

161

Ma liste de changements après le passage à Rails 5:

  1. Placez libdir dans appcar tout le code à l'intérieur de l'application est chargé automatiquement dans le développement et chargé avec impatience dans prod et, plus important encore, est chargé automatiquement en développement afin que vous n'ayez pas à redémarrer le serveur à chaque fois que vous apportez des modifications.
  2. Supprimez toutes les requireinstructions pointant vers vos propres classes à l'intérieur libcar elles sont toutes chargées automatiquement si leur nom de fichier / répertoire est correct, et si vous laissez des requireinstructions, cela peut interrompre le chargement automatique. Plus d'infos ici
  3. Défini config.eager_load = truedans tous les environnements pour voir les problèmes de chargement de code avec impatience dans dev.
  4. À utiliser Rails.application.eager_load!avant de jouer avec les threads pour éviter les erreurs de «dépendance circulaire».
  5. Si vous avez des extensions ruby ​​/ rails, laissez ce code dans l'ancien librépertoire et chargez-les manuellement depuis l'initialiseur. Cela garantira que les extensions sont chargées avant votre logique supplémentaire qui peut en dépendre:

    # config/initializers/extensions.rb
    Dir["#{Rails.root}/lib/ruby_ext/*.rb"].each { |file| require file }
    Dir["#{Rails.root}/lib/rails_ext/*.rb"].each { |file| require file }
Lev Lukomsky
la source
8
Alors, comment utilise-t-on le libdossier maintenant? Je veux dire, déplacer libdir dans appdir semble un peu comme une solution de contournement.
Martin Svoboda
3
/app/lib/placé un fichier / classe et ce n'est PAS un chargement automatique. testé dans les rails 5.1, nouveau projet
Tim Kretschmer
29
Il est à noter que vous devez arrêter le printemps. J'ai tout déplacé vers app / lib / puis j'ai perdu un peu de temps à me demander pourquoi je ne pouvais toujours pas utiliser mes classes depuis la console. spring stop ftw :)
jacklin
1
Où irait la ligne suivanteRails.application.eager_load!
Steven Aguilar
1
Cela peut fonctionner mais ce n'est pas la meilleure solution. La structure des dossiers est également sémantique. Les choses dans libont une proximité perçue différente avec le projet que les choses dans l' appannuaire. Plusieurs des autres réponses sont meilleures que celle-ci.
CWitty
84

Je viens d'utiliser config.eager_load_pathsau lieu de config.autoload_pathsmentionner comme mention akostadinov sur le commentaire github: https://github.com/rails/rails/issues/13142#issuecomment-275492070

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

Il fonctionne sur l'environnement de développement et de production.

Merci Johan pour la suggestion de remplacer #{Rails.root}/libpar Rails.root.join('lib')!

Michał Zalewski
la source
3
Fonctionne comme un charme. Je n'aimais pas la syntaxe, alors je l'ai changée en config.eager_load_paths << Rails.root.join('lib').
3limin4t0r
2
Pour moi, c'était la meilleure réponse. Mon projet a commencé sur Rails 5.2 à partir de zéro et le dossier / lib était toujours créé en dehors du dossier / app. Je n'ai pas vu de bonne raison de le déplacer.
Samir Haddad
1
Oui, cela fonctionne! Il semble que les développeurs de Rails aiment vraiment causer des problèmes de chargement de bibliothèques: D jusqu'à la prochaine fois!
Damien Roche
To Rails 5.2 utilise à la config.eager_load_paths += [Rails.root.join('lib')]place parce que config.eager_load_pathsc'est un tableau gelé
William Wong Garay
@WilliamWongGaray config.eager_load_paths est en lecture seule lorsque vous essayez de le modifier dans l'initialiseur. Lorsque vous ajoutez des chemins, application.rbcela fonctionnera en utilisant les deux méthodes.
Michał Zalewski
31

Le chargement automatique est désactivé dans l'environnement de production en raison de la sécurité des threads. Merci à @ Зелёный pour le lien.

J'ai résolu ce problème en stockant les fichiers lib dans un libdossier de mon apprépertoire comme recommandé sur Github . Chaque dossier du appdossier est chargé automatiquement par Rails.

Tobias
la source
6
Si vous ne voulez pas fouiller dans le long fil de discussion sur Github, vous pouvez trouver une explication distillée ici: collectiveidea.com/blog/archives/2016/07/22/...
Ernest
7
J'ai utilisé config.eager_load_paths << "#{Rails.root}/lib", c'est mieux IMO pour suivre la structure de l'application de rails recommandée.
akostadinov
2
La mise en place de lib app/libest recommandée par les membres de rails github.com/rails/rails/issues/13142#issuecomment-275549669
eXa
4
Cela ruine complètement le but lib. J'attendrais que Tenderlove ou DHH interviennent. En attendant, je recommanderais (personnellement) de m'en tenir à la réponse de @Lev Lukomsky.
Josh Brody
@JoshBrody Mon opinion est maintenant que vous ne devriez pas du tout avoir besoin du /librépertoire. Les bibliothèques tierces sont la plupart du temps des gemmes et sinon, une gemme devrait être créée. Pour les autres fichiers, je crée des dossiers spécifiques dans le /apprépertoire. Par exemple validators.
Tobias
22

Il doit y avoir une raison pour laquelle le chargement automatique est désactivé par défaut en production.

Voici une longue discussion sur cette question. https://github.com/rails/rails/issues/13142

Зелёный
la source
1
Cette discussion est la meilleure source d'informations sur le sujet que j'ai rencontrée, bien que longue lecture.
Jason le
12

Cela permet de charger automatiquement la librairie et fonctionne également dans l'environnement de production.

PS J'ai changé ma réponse, maintenant cela ajoute aux deux chemins de chargement automatique, quel que soit l'environnement, pour permettre également de travailler dans des environnements personnalisés (comme la scène)

# config/initializers/load_lib.rb
...
config.eager_load_paths << Rails.root.join('lib')
config.autoload_paths << Rails.root.join('lib')
...
srghma
la source
2
Pourriez-vous expliquer pourquoi cela résout le problème?
Stuart.Sklinar
@ Stuart.Sklinar cela permet de recharger automatiquement la librairie, et fonctionne également dans l'environnement de production. PS J'ai changé ma réponse, maintenant cela ajoute à la fois impatient - et les chemins de chargement automatique, quel que soit l'environnement, pour permettre également de travailler dans des environnements personnalisés (comme la scène)
srghma
1
Pourriez-vous développer (dans votre réponse)? Les réponses au code uniquement n'aident pas vraiment quiconque à comprendre pourquoi cela devrait être fait "de cette façon" - je devrais ajouter que je ne suis pas un développeur Ruby, juste aider à clarifier SO. Ajouter un commentaire à une "réponse code seulement" lui donnerait un contexte réel.
Stuart.Sklinar
1
@ Stuart.Sklinar sure
srghma
6

Changez simplement config.autoload_paths en config.eager_load_paths dans le fichier config / application.rb. Parce que dans les rails 5, le chargement automatique est désactivé par défaut pour l'environnement de production. Pour plus de détails, veuillez suivre le lien .

 #config.autoload_paths << "#{Rails.root}/lib"
  config.eager_load_paths << Rails.root.join('lib')

Cela fonctionne à la fois pour le développement de l'environnement et la production.

Jitendra Rathor
la source
4

Dans un certain sens, voici une approche unifiée dans Rails 5 pour centraliser la configuration hâte et chargement automatique, en même temps, il ajoute le chemin de chargement automatique requis chaque fois que la charge hâtive est configurée, sinon il ne pourra pas fonctionner correctement:

# config/application.rb
...
config.paths.add Rails.root.join('lib').to_s, eager_load: true

# as an example of autoload only config
config.paths.add Rails.root.join('domainpack').to_s, autoload: true
...
pocheptsov
la source
2

Pour quiconque a eu du mal avec cela comme moi, il ne suffit pas de placer un répertoire sous app/. Oui, vous obtiendrez un chargement automatique mais pas un rechargement nécessaire , ce qui nécessite le respect des conventions d'espacement de noms .

De plus, l'utilisation de l'initialiseur pour charger l'ancien niveau racine libempêchera le rechargement de la fonction pendant le développement.

Abdullah Barrak
la source
0

Le déplacement du dossier lib vers l'application a permis de résoudre un problème, mon API Twitter ne fonctionnait pas en production. J'avais "TwitterApi constant non initialisé" et mon API Twitter était dans mon dossier lib. J'avais config.autoload_paths += Dir["#{Rails.root}/app/lib"]dans mon application.rb mais cela n'a pas fonctionné avant de déplacer le dossier.

Cela a fait l'affaire

Laurie
la source
-6

pour résumer la réponse de Lev: mv lib appétait suffisant pour que tout mon libcode soit rechargé / rechargé automatiquement.

(rails 6.0.0beta3 mais devrait fonctionner correctement sur les rails 5.x aussi)

localhostdotdev
la source