2009-07-02 10 views
76

Je suis en train d'écrire un wrapper personnalisé pour open_flash_chart plugin. Il est placé dans /lib et le charger comme un module dans ApplicationController.Rails/lib modules et

Cependant, j'ai un problème de hiérarchie ou de classe.

De tout contrôleur je peux accéder à open_flash_chart fonctions OpenFlashChart, Line etc

Cependant, dans une classe dans un module /lib, il ne fonctionne pas!

Des idées?

Répondre

143

Il y a deux façons que les fichiers sont chargés dans Rails:

  • Il est inscrit dans le processus de chargement automatique, et vous faites référence à une constante qui correspond au nom de fichier. Par exemple, si vous avez app/controllers/pages_controller.rb et référence PagesController, app/controllers/pages_controller.rb sera automatiquement chargé. Cela se produit pour une liste prédéfinie de répertoires dans le chemin de chargement. C'est une fonctionnalité de Rails, et ne fait pas partie du processus de chargement Ruby normal.
  • Les fichiers sont explicitement require d. Si un fichier est require d, Ruby parcourt la liste complète des chemins dans vos chemins de chargement et trouve le premier cas où le fichier require d se trouve dans le chemin de chargement. Vous pouvez voir le chemin de chargement entier en inspectant $ LOAD_PATH (un alias pour $ :).

Depuis lib est dans votre chemin de charge, vous avez deux options: soit le nom, vos fichiers avec les mêmes noms que les constantes, donc Rails les ramasser automatiquement lorsque vous faites référence à la constante en question, ou exiger explicitement la module. Je remarque également que vous pourriez être confus au sujet d'une autre chose. ApplicationController est et non l'objet racine dans le système. Observer.

module MyModule 
    def im_awesome 
    puts "#{self} is so awesome" 
    end 
end 

class ApplicationController < ActionController::Base 
    include MyModule 
end 

class AnotherClass 
end 

AnotherClass.new.im_awesome 
# NoMethodError: undefined method `im_awesome' for #<AnotherClass:0x101208ad0> 

Vous devrez inclure le module dans quelque classe que vous voulez l'utiliser dans

class AnotherClass 
    include MyModule 
end 

AnotherClass.new.im_awesome 
# AnotherClass is so awesome 

Bien sûr, afin de pouvoir inclure le module en premier lieu, vous devrez l'avoir disponible (en utilisant l'une des techniques ci-dessus).

+2

voulait ajouter: Si l'un de vos modules dans/lib (ou dans l'un des répertoires de chargement automatique) est déjà défini; Par exemple, vous surchargez ActiveRecord ou String, vous devrez l'exiger explicitement ou il ne sera pas chargé – Mike

+1

étrangement, j'obtiens: GaClient non initialisé (NameError), sauf si j'ai besoin de 'ga_client' au préalable (la classe est définie dans lib/ga_client.rb). Existe-t-il une documentation pour le schéma de dénomination Autoload? – mkirk

80

Dans Rails 3/les modules lib ne sont pas chargés automatiquement.

En effet, la ligne:

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

dans config/application.rb est commenté.

Vous pouvez essayer de décommenter cette ligne ou, (cela a fonctionné encore mieux pour moi), laisser commenté (pour référence future) et ajouter ces deux lignes:

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

Cela dupliquera le chemin '../ lib' dans le tableau' ApplicationName :: Application.config.autoload_paths'. – jibiel

+1

@jibiel alors quelle est la résolution ici? – ylluminate

+0

je ne sais pas, mais cela a fonctionné ok .. :) – Orlando

19

Ce qui a fonctionné pour moi, en plus décommentant config.autoload_paths (je suis sur Rails 3.1.3), était de créer un initialiseur comme ceci:

#config/initializers/myapp_init.rb 
require 'my_module'  
include MyModule 

De cette façon, je peux appeler des méthodes de mymodule de partout et que les méthodes de classe Model.mymodule_method ou méthodes d'instance mymodel.mymodule_method

Peut-être que certains experts peuvent expliquer les implications de cela. À présent, utilisez-le à vos risques et périls.

Edit: Ensuite, je pense mieux approuch serait:

créer un initialiseur comme ceci:

#config/initializers/myapp_init.rb 
require ‘my_module’ 

Inclure le module en cas de besoin, comme ceci:

1) Si vous voulez l'utiliser comme "Méthodes de classe", utilisez "étendre":

class Myclass < ActiveRecord::Base 
    extend MyModule 
    def self.method1 
     Myclass.my_module_method 
    end 
end 

2) si vous voulez l'utiliser comme « Méthodes d'instance » inclure dans la définition de la classe:

class Myclass < ActiveRecord::Base 
include MyModule 
    def method1 
     self.my_module_method 
    end 
end 

3) se rappeler que include MyModule fait référence à un fichier my_module.rb dans votre chemin de charge qui doit être d'abord nécessaire

+3

J'ai créé mon module sur le dossier 'lib', donc j'ai ajouté le fichier' config.autoload_paths + =% W (# {config.root}/lib) 'sur le fichier' config/application.rb'. Après cela, j'ai suivi votre suggestion d'ajouter le fichier 'config/initializers/myapp_init.rb' et son contenu. Tout est bon. Merci beaucoup :) –

+0

Même si 'require' fonctionne pour moi et le chargement automatique ne fonctionne pas (méthode de module non défini), [ce commentaire dit que vous ne devriez pas utiliser' require'] (http://stackoverflow.com/questions/ 3356742/best-way-to-charger-module-class-from-lib-folder-in-rails-3 # comment3541227_3376401). – Dennis

0

Il se peut que vous vouliez charger explicitement le (s) fichier (s) sous le répertoire lib au moment de l'initialisation de l'application.
Dans ma config/application.rb, j'ai une entrée sous,
config.autoload_paths += %W(#{config.root}/lib)

Il se peut aussi que le nom/la hiérarchie du module ne soit pas le même que dans le fichier ou l'emplacement/le nom du fichier n'est pas le même que la hiérarchie , donc le chargement automatique de ce fichier est également impossible. Donc, quand j'ai ajouté une entrée au bas de config/application.rb comme,
require "./lib/file_name_without_extention
cela a bien fonctionné.

2

Pour utiliser le module lib/my_module.rb dans vos modèles et contrôleurs:

En config/application.rb:

config.watchable_dirs['lib'] = [:rb] 

Dans votre modèle (idée similaire pour votre contrôleur):

require_dependency 'my_module' 

class MyModel < ActiveRecord::Base 
    include MyModule 

    MyModule.some_method 
end 

Cette méthode est décrit plus en détail à http://hakunin.com/rails3-load-paths