web-dev-qa-db-fra.com

Rails/lib modules et

J'écris un wrapper personnalisé pour le plugin open_flash_chart. Il est placé dans /lib et le charge en tant que module dans ApplicationController.

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

Depuis n'importe quel contrôleur, je peux accéder aux fonctions open_flash_chart en tant que OpenFlashChart, Line etc.

Cependant, dans une classe d'un module /lib, cela ne fonctionne pas!

Des idées?

78
Mantas

Les fichiers sont chargés dans Rails de deux manières:

  • Il est enregistré dans le processus de chargement automatique et vous référencez une constante qui correspond au nom du 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. Ceci est une fonctionnalité de Rails et ne fait pas partie du processus de chargement Ruby normal.
  • Les fichiers sont explicitement required. Si un fichier est required, Ruby parcourt la liste complète des chemins dans vos chemins de chargement et trouve le premier cas où le fichier que vous avez required se trouve dans le chemin de chargement. Vous pouvez voir le chemin de chargement complet en inspectant $ LOAD_PATH (un alias pour $ :).

Puisque lib se trouve dans votre chemin de chargement, vous avez deux options: nommer vos fichiers avec les mêmes noms que les constantes. Rails les prendra automatiquement lorsque vous référencez la constante en question ou exigez explicitement le module.

Je remarque également que vous pourriez être confus sur une autre chose. ApplicationController est not l'objet racine du 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 la classe dans laquelle vous souhaitez l’utiliser.

class AnotherClass
  include MyModule
end

AnotherClass.new.im_awesome
# AnotherClass is so awesome

Bien entendu, pour pouvoir inclure le module en premier lieu, vous devez le disposer (en utilisant l'une des techniques ci-dessus).

145
Yehuda Katz

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

C'est parce que la ligne:

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

inside config/application.rb est commenté.

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

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

Ce qui a fonctionné pour moi, outre le fait de ne pas commenter config.autoload_paths (je suis sur Rails 3.1.3), a été de créer un initialiseur comme celui-ci:

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

De cette façon, je peux appeler les méthodes mymodule de n'importe où et en tant que méthodes de classe Model.mymodule_method ou en tant que méthodes d'instance mymodel.mymodule_method

Peut-être qu'un expert peut expliquer les implications de cela. A présent, utilisez-le à vos risques et périls.

Edit: Après, je pense qu'un meilleur approuch serait:

créez un initialiseur comme ceci:

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

Incluez le module si nécessaire, comme ceci:

1) si vous voulez l’utiliser en tant que "Méthodes de classe", utilisez "extend":

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", incluez-le dans la définition de classe:

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

3) rappelez-vous que include MyModule fait référence à un fichier my_module.rb dans votre chemin de chargement qui doit être requis en premier

21
Fernando Fabreti

Il se peut que vous souhaitiez explicitement charger un ou plusieurs fichiers dans le répertoire lib au moment de l’initialisation de l’application.
Dans ma config/application.rb, j'ai une entrée comme,
config.autoload_paths += %W(#{config.root}/lib)

Cela pourrait également être le cas si le nom/la hiérarchie du module n’est pas identique à celui indiqué dans le fichier ou l’emplacement/le nom du fichier n’est pas identique à cette hiérarchie; le chargement automatique de ce fichier n’est donc pas possible. Donc, quand j'ai ajouté une entrée au bas de config/application.rb en tant que,
require "./lib/file_name_without_extention
Cela a bien fonctionné.

0
Swapnil Chincholkar