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?
Es gibt zwei Möglichkeiten, Dateien in Rails zu laden:
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.require
d. Wenn es sich bei einer Datei um require
d handelt, durchsucht Ruby die gesamte Liste der Pfade in Ihren Ladepfaden und sucht nach dem ersten Fall, in dem sich die Datei, die Sie require
d 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).
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/**/"]
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
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
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.