webentwicklung-frage-antwort-db.com.de

Rails/lib-Module und

Ich schreibe einen benutzerdefinierten Wrapper für open_flash_chart Plugin. Es befindet sich in /lib und lädt es als Modul in ApplicationController.

Ich habe jedoch ein Klassenhierarchie- oder ein smth-Problem.

Von jedem Controller kann ich auf open_flash_chart-Funktionen als OpenFlashChart, Line etc zugreifen

In einer Klasse in einem /lib-Modul funktioniert es jedoch nicht!

Irgendwelche Ideen?

78
Mantas

Es gibt zwei Möglichkeiten, Dateien in Rails zu laden:

  • Sie wird im Autoload-Prozess registriert und Sie referenzieren eine Konstante, die dem Dateinamen entspricht. Wenn Sie beispielsweise app/controllers/pages_controller.rb und einen Verweis auf PagesController haben, wird app/controllers/pages_controller.rb automatisch geladen. Dies geschieht für eine voreingestellte Liste von Verzeichnissen im Ladepfad. Dies ist eine Funktion von Rails und nicht Teil des normalen Ruby-Ladeprozesses.
  • Dateien sind explizit required. Wenn es sich bei einer Datei um required handelt, durchsucht Ruby die gesamte Liste der Pfade in Ihren Ladepfaden und sucht nach dem ersten Fall, in dem sich die Datei, die Sie required im Ladepfad befindet. Sie können den gesamten Ladepfad sehen, indem Sie $ LOAD_PATH (einen Alias ​​für $ :) überprüfen.

Da sich lib in Ihrem Ladepfad befindet, haben Sie zwei Möglichkeiten: Benennen Sie Ihre Dateien mit denselben Namen wie die Konstanten. Rails wird sie also automatisch abrufen, wenn Sie auf die betreffende Konstante verweisen.

Ich stelle auch fest, dass Sie über etwas anderes verwirrt sein könnten. ApplicationController ist nicht das Wurzelobjekt im System. Beobachten:

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>

Sie müssen das Modul in die Klasse aufnehmen, in der Sie es verwenden möchten.

class AnotherClass
  include MyModule
end

AnotherClass.new.im_awesome
# AnotherClass is so awesome

Um das Modul überhaupt einbinden zu können, müssen Sie es zur Verfügung haben (mit einer der beiden oben genannten Techniken).

145
Yehuda Katz

In Rails 3/lib werden Module nicht automatisch geladen.

Dies ist, weil die Zeile:

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

inside config/application.rb ist kommentiert.

Sie können versuchen, diese Zeile auszukommentieren, oder (es funktionierte für mich noch besser), lassen Sie dies kommentiert (zur späteren Verwendung) und fügen Sie diese beiden Zeilen hinzu:

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

Was für mich neben der Kommentierung von config.autoload_paths (ich bin auf Rails 3.1.3) funktionierte, war das Erstellen eines Initialisierers wie folgt:

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

Auf diese Weise kann ich mymodule-Methoden von überall und als Klassenmethoden Model.mymodule_method oder als Instanzmethoden mymodel.mymodule_method aufrufen

Vielleicht kann ein Experte die Auswirkungen erklären. Verwenden Sie es jetzt auf eigenes Risiko.

Edit: Danach denke ich, ein besserer Ansatz wäre:

erstellen Sie einen Initialisierer wie folgt:

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

Fügen Sie das Modul bei Bedarf so hinzu:

1) Wenn Sie es als "Klassenmethoden" verwenden möchten, verwenden Sie "Erweitern":

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

2) Wenn Sie es als "Instanzmethoden" verwenden möchten, schließen Sie es in die Klassendefinition ein:

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

3) Denken Sie daran, dass include MyModule auf eine Datei my_module.rb in Ihrem Ladepfad verweist, die zuerst erforderlich sein muss

21

So verwenden Sie das Modul lib/my_module.rb in Ihren Modellen und Steuerungen:

Im config/application.rb:

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

In Ihrem Modell (ähnliche Idee für Ihren Controller):

require_dependency 'my_module'

class MyModel < ActiveRecord::Base
  include MyModule

  MyModule.some_method
end

Diese Methode wird unter http://hakunin.com/Rails3-load-paths ausführlicher beschrieben

2
Dennis

Möglicherweise möchten Sie die Datei (en) zum Zeitpunkt der Anwendungsinitialisierung explizit im Verzeichnis lib laden.
In meiner config/application.rb habe ich einen Eintrag als,
config.autoload_paths += %W(#{config.root}/lib)

Dies kann auch der Fall sein, wenn der Name/die Hierarchie des Moduls nicht mit dem in der Datei übereinstimmt oder der Speicherort/Name der Datei nicht mit dieser Hierarchie übereinstimmt. Daher ist ein automatisches Laden dieser Datei ebenfalls nicht möglich. Als ich also einen Eintrag unten in config/application.rb als hinzufügte,
require "./lib/file_name_without_extention
es hat gut funktioniert.

0