Модули Rails/lib и
Я пишу пользовательскую оболочку для плагина open_flash_chart
. Он помещается в /lib
и загружает его как модуль в ApplicationController
.
Однако у меня есть некоторая иерархия классов или проблема smth.
От любого контроллера я могу получить доступ к open_flash_chart
функциям как OpenFlashChart
, Line
и т.д.
Однако в классе в модуле /lib
он не работает!
Любые идеи?
Ответы
Ответ 1
Есть два способа загрузки файлов в Rails:
- Он зарегистрирован в процессе автозагрузки и ссылается на константу, соответствующую имени файла. Например, если у вас есть
app/controllers/pages_controller.rb
и reference PagesController, автоматически загружается app/controllers/pages_controller.rb
. Это происходит для предварительно заданного списка каталогов в пути загрузки. Это функция Rails и не является частью обычного процесса загрузки Ruby.
- Файлы явно
require
d. Если файл require
d, Ruby просматривает весь список путей в ваших путях загрузки и находит первый случай, когда файл require
d находится в пути загрузки. Вы можете увидеть весь путь загрузки, проверив $LOAD_PATH (псевдоним для $:).
Так как lib
находится в вашем пути загрузки, у вас есть два варианта: либо назовите свои файлы с теми же именами, что и константы, поэтому Rails автоматически подберет их, когда вы ссылаетесь на указанную константу, или явно требуется модуль.
Я также замечаю, что вас может смутить другая вещь. ApplicationController - это не корневой объект в системе. Обратите внимание:
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>
Вам нужно будет включить модуль в любой класс, в который вы хотите его использовать.
class AnotherClass
include MyModule
end
AnotherClass.new.im_awesome
# AnotherClass is so awesome
Конечно, чтобы иметь возможность включить модуль в первую очередь, вам нужно иметь его доступным (используя любой из вышеперечисленных методов).
Ответ 2
В Rails 3/lib модули не загружаются автоматически.
Это потому, что строка:
# config.autoload_paths += %W(#{config.root}/extras)
внутри config/application.rb прокомментирован.
Вы можете попытаться раскомментировать эту строку или (это сработало еще лучше для меня), оставьте это комментарий (для справки в будущем) и добавьте две строки:
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Ответ 3
Что сработало для меня, помимо раскомментирования config.autoload_paths (Im on Rails 3.1.3), было создание инициализатора следующим образом:
#config/initializers/myapp_init.rb
require 'my_module'
include MyModule
Таким образом, я могу вызывать методы mymodule из любого места и как методы класса Model.mymodule_method
или как методы экземпляра mymodel.mymodule_method
Возможно, какой-то эксперт может объяснить последствия этого. В настоящее время используйте его на свой страх и риск.
Изменить:. После этого я думаю, что лучше всего будет:
создайте инициализатор следующим образом:
#config/initializers/myapp_init.rb
require ‘my_module’
Включите модуль, где необходимо, например:
1), если вы хотите использовать его как "Методы классов", используйте "extend":
class Myclass < ActiveRecord::Base
extend MyModule
def self.method1
Myclass.my_module_method
end
end
2), если вы хотите использовать его как "Методы экземпляра", включите его в определение класса:
class Myclass < ActiveRecord::Base
include MyModule
def method1
self.my_module_method
end
end
3) помните, что include MyModule
относится к файлу my_module.rb
в вашем пути загрузки, который должен быть необходим сначала
Ответ 4
Чтобы использовать модуль lib/my_module.rb
в ваших моделях и контроллерах:
В config/application.rb
:
config.watchable_dirs['lib'] = [:rb]
В вашей модели (аналогичная идея для вашего контроллера):
require_dependency 'my_module'
class MyModel < ActiveRecord::Base
include MyModule
MyModule.some_method
end
Этот метод более подробно описан в http://hakunin.com/rails3-load-paths
Ответ 5
Возможно, вы захотите явно загрузить файл в каталоге lib во время инициализации приложения.
В моем config/application.rb у меня есть запись as,
config.autoload_paths += %W(#{config.root}/lib)
Также это может быть так, что имя/иерархия модуля не такое же, как в файле или местоположении/имя файла не совпадает с этой иерархией, поэтому автоматическая загрузка этого файла также невозможна. Поэтому, когда я добавил запись внизу config/application.rb как, require "./lib/file_name_without_extention
, она работала нормально.