Модули 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 , она работала нормально.