Лучший способ загрузить модуль / класс из папки lib в Rails 3?

262

Поскольку последняя версия Rails 3 не является автоматической загрузкой модулей и классов из lib, что было бы лучшим способом загрузить их?

Из github:

A few changes were done in this commit:

Do not autoload code in *lib* for applications (now you need to explicitly 
require them). This makes an application behave closer to an engine 
(code in lib is still autoloaded for plugins);
Теги:
class
module
autoload
ruby-on-rails-3

11 ответов

245
Лучший ответ

Как и в случае с Rails 2.3.9, в config/application.rb есть параметр, в котором вы можете указать каталоги, содержащие файлы, которые вы хотите загрузить.

Из приложения .rb:

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
  • 7
    Обратите внимание на ответ @ thankful также, если вы хотите автоматически загрузить все поддерево app/lib .
194
# Autoload lib/ folder including all subdirectories
config.autoload_paths += Dir["#{config.root}/lib/**/"]

Источник: Rails 3 Quicktip: каталог Autoload lib, включая все подкаталоги, избегает ленивой загрузки

Обратите внимание, что файлы, содержащиеся в папке lib, загружаются только при запуске сервера. Если вам нужен комфорт для автозагрузки этих файлов, прочитайте: Rails 3 Quicktip: автоматически перезагружает папки lib в режиме разработки. Имейте в виду, что это не предназначено для производственной среды, поскольку постоянная перезагрузка замедляет работу машины.

  • 0
    Ссылки мертвы
82

Магия автозагрузки

Я думаю, что опция, управляющая папками, из которых выполняется загрузка автозагрузки, была достаточно освещена в других ответах. Однако, если у кого-то есть проблемы с загруженными материалами, хотя у них были изменены пути автозагрузки, тогда этот ответ пытается объяснить, что является волшебством этой автозагрузки.

Итак, когда дело доходит до загрузки файлов из подкаталогов, вы получаете информацию или соглашение, о котором вы должны знать. Иногда магия Ruby/Rails (на этот раз в основном Rails) может затруднить понимание, почему что-то происходит. Любой модуль, объявленный в пути автозагрузки, будет загружен только в том случае, если имя модуля соответствует имени родительского каталога. Поэтому, если вы попытаетесь ввести lib/my_stuff/bar.rb что-то вроде:

module Foo
  class Bar
  end
end

Он не будет загружен автоматически. Затем снова, если вы переименуете родительский каталог в foo, таким образом, разместив свой модуль по пути: lib/foo/bar.rb. Он будет там для вас. Другой вариант - назвать файл, который вы хотите загрузить с помощью имени модуля. Очевидно, что тогда может быть только один файл. Если вам нужно разделить свои материалы на многие файлы, вы, конечно, можете использовать этот файл для других файлов, но я не рекомендую это, потому что тогда, когда в режиме разработки и вы изменяете эти другие файлы, Rails не может автоматически перезагрузите их для вас. Но если вы действительно хотите, чтобы у вас мог быть один файл по имени модуля, который затем указывает фактические файлы, необходимые для использования модуля. Таким образом, у вас может быть два файла: lib/my_stuff/bar.rb и lib/my_stuff/foo.rb, а первый - тот же, что и выше, а последний содержит одну строку: require "bar", и это будет работать одинаково.

P.S. Я вынужден добавить еще одну важную вещь. В последнее время, когда я хочу иметь что-то в каталоге lib, которое должно получить автозагрузку, я, как правило, начинаю думать, что если это то, что я действительно разрабатываю специально для этого проекта (как правило, это может быть когда-нибудь превратитесь в "статический" фрагмент кода, используемый во многих проектах или подмодуль git и т.д., и в этом случае он определенно должен быть в папке lib), возможно, его место вообще не находится в папке lib. Возможно, это должно быть в подпапке под папкой приложения. У меня такое ощущение, что это новый способ делать рельсы. Очевидно, что та же магия в работе везде, где вы загружаете автозагрузочные пути, ставите свои вещи так, чтобы это было хорошо для этих вещей. Во всяком случае, это только мои мысли по этому вопросу. Вы можете не согласиться.:)


ОБНОВЛЕНИЕ: О типе магии.

Как отметил Серин в своем комментарии, ядро ​​ "автозагрузка модуля" уверенно является частью Ruby, но это не относится к файлам автозагрузки. Для Rails вам не нужны autoload :Foo, File.join(Rails.root, "lib", "my_stuff", "bar"). И когда вы попытаетесь впервые ссылаться на модуль Foo, он будет загружен для вас. Однако, что делает Rails, это дает нам возможность автоматически загружать материал из зарегистрированных папок, и это было реализовано таким образом, что ему нужно что-то принять в соглашениях об именах. Если бы это не было реализовано так, то каждый раз, когда вы ссылаетесь на то, что в настоящее время не загружено, ему придется проходить через все файлы во всех папках автозагрузки и проверять, содержит ли кто-нибудь из них то, что вы пытались ссылаться. Это, в свою очередь, победит идею автозагрузки и автозагрузки. Однако, используя эти соглашения, вы можете вычесть из модуля/класса вашу попытку загрузить, где это может быть определено, и просто загрузить это.

  • 1
    Почему это магия Рубина? Ruby просто предоставляет функцию автозагрузки Module #, которую вы можете использовать для команды загрузки файла при доступе к (неопределенной) константе (см. Ruby-doc.org/core-1.9.3/Module.html#method-i-autoload ). Сопоставление имен модулей / классов с каталогами / файлами, по моему мнению, выполняется в Rails / ActiveSupport (например, здесь: github.com/rails/rails/blob/… ). Я ошибся?
  • 0
    Да, я верю, что вы правы. Я был слишком поспешен, чтобы «исправить» свой первоначальный ответ, когда Забба указал на его «недостаток». Позвольте мне обновить мой ответ немного больше, чтобы прояснить этот вопрос.
Показать ещё 4 комментария
38

Предупреждение: если вы хотите загрузить "патч обезьяны" или "открыть класс" из своей папки "lib", не используйте подход автозагрузка"!!!

  • "config.autoload_paths": работает только если вы загружаете класс, определенный только в ОДНОМ месте. Если какой-либо класс уже определен где-то в другом месте, то вы не можете загрузить его снова с помощью этого подхода.

  • "config/initializer/load_rb_file.rb" подход: всегда работает! независимо от того, какой класс-класс является новым классом или "открытым классом" или "патчем обезьяны" для существующего класса, он всегда работает!

Подробнее см. https://stackoverflow.com/questions/4235782/rails-3-library-not-loading-until-require

  • 6
    Это критическое различие для понимания. Спасибо за это.
26

Очень похоже, но я думаю, что это немного более элегантно:

config.autoload_paths += Dir["#{config.root}/lib", "#{config.root}/lib/**/"]
12

В моем случае я пытался просто загрузить файл непосредственно в каталоге lib.

Внутри application.rb...

require '/lib/this_file.rb' 

не работал, даже в консоли, а затем, когда я попытался

require './lib/this_file.rb' 

и рельсы загружают файл отлично.

Я все еще довольно нооб, и я не уверен, почему это работает, но оно работает. Если кто-то хотел бы объяснить это мне, я был бы признателен: D Я надеюсь, что это поможет кому-то в любом случае.

  • 2
    Это потому, что ./lib/this_file.rb ищет в текущем каталоге (в консоли Rails это будет корень вашего Rails), а /lib/this_file.rb ищет его как абсолютный путь. Пример: ./lib/this_file.rb = /var/www/myrailsapp/lib/this_file.rb, /lib/this_file.rb = /lib/this_file.rb
7

У меня была та же проблема. Вот как я это решил. Решение загружает каталог lib и все подкаталоги (а не только прямые). Конечно, вы можете использовать это для всех каталогов.

# application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
  • 5
    Это имеет неприятный побочный эффект от полного нарушения соглашений о пространствах имен Rails. Если lib / bar / foo.rb, определяющий Bar :: Foo, появляется раньше, чем lib / foo.rb, определяющий Foo в поиске автозагрузки, то вы получите непонятные ошибки, такие как Expected lib/bar/foo.rb to define constant Foo если вы попытаетесь загрузить lib / foo.rb, ссылаясь на константу Foo.
5

config.autoload_paths не работает для меня. Я решаю это другим способом

Ruby on rails 3 не выполняет автоматический перезагрузку (автозагрузка) кода из папки /lib. Я решаю это, вставив внутри ApplicationController

Dir["lib/**/*.rb"].each do |path|
  require_dependency path
end 
3

Если только определенные файлы нуждаются в доступе к модулям в lib, просто добавьте инструкцию require к файлам, которые в ней нуждаются. Например, если одной модели необходимо получить доступ к одному модулю, добавьте:

require 'mymodule'

в верхней части файла model.rb.

  • 50
    Вы не должны использовать require в приложении rails, потому что это предотвращает [un] загрузку этого кода ActiveSupport::Dependencies . Вместо этого вы должны использовать config.autoload_paths как ответ выше, а затем включить / расширить, как требуется.
  • 69
    Благодарю. Оставив здесь этот ответ, чтобы другие могли учиться на моей ошибке ...
Показать ещё 4 комментария
1

Есть несколько причин, по которым у вас могут возникнуть проблемы с загрузкой из lib - см. здесь для деталей - http://www.williambharding.com/blog/technology/rails-3-autoload-modules-and-classes-in-production/

  • исправить путь автозагрузки
  • связанных с потоками
  • присвоение имен
  • ...
0

Заполните имя файла правильно.

Серьезно. Я сражался с классом в течение часа, потому что класс был Governance:: ArchitectureBoard, и файл находился в lib/management/architecture_baord.rb(транспонированный O и A на "доске" )

Кажется очевидным в ретроспективе, но это было отслеживание дьявола. Если класс не определен в файле, который Rails ожидает, что он будет основан на изменении имени класса, он просто не найдет его.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню