Rails 5: загрузка файлов lib в продакшене

128

Я обновил одно из своих приложений с Rails 4.2.6 до Rails 5.0.0. В Руководстве по обновлению говорится, что функция автозагрузки теперь по умолчанию отключена в производственной среде.

Теперь я всегда получаю сообщение об ошибке на своем производственном сервере, так как загружаю все файлы lib с автозагрузкой в application.rbфайл.

module MyApp
    class Application < Rails::Application
        config.autoload_paths += %W( lib/ )
    end
end

На данный момент я установил config.enable_dependency_loadingзначение, trueно мне интересно, есть ли лучшее решение для этого. Должна быть причина, по которой автозагрузка отключена в производственной среде по умолчанию.

Тобиас
источник
сумасшедшая вещь, и документы по-прежнему говорят вам делать auto_load. Я был очень сбит с толку, что происходит не так в производственной среде для нового приложения. И так как я начал изучать Rails 5, я не читал руководства по миграции. Я подал документ о проблеме, чтобы, надеюсь, решить эту проблему: github.com/rails/rails/issues/27268
akostadinov
1
удивительно, у меня есть два файла в каталоге lib, один файл легко доступен во время выполнения, а другой нужно
иллюзионист
@Tobias Какое решение вы в итоге выбрали?
geoboy
@geoboy Я группирую код (например Validators) в папки прямо в каталоге app /, поскольку там код загружается автоматически.
Tobias
речь идет о правильном пути к файлу и определение класса здесь , что работа для меня в Rails 5.2: Путь к файлу: app/services/paylinx/paylinx_service.rbОпределение класса: module Paylinx class PaylinxService end end. Я пробовал эти autoload_pathsштуки. у меня не работает.
NamNamNam

Ответы:

161

Мой список изменений после перехода на Rails 5:

  1. Место libреж в appпотому , что весь код внутри приложения будет автоматически загружаются в разработчика и нетерпеливый загружены в прод и самое главное это autoreloaded в развитии , так что вам не нужно перезагружать сервер каждый раз , когда вы делаете изменения.
  2. Удалите все requireоператоры, указывающие на ваши собственные классы внутри, libпотому что все они в любом случае автоматически загружаются, если их имена файлов / каталогов верны, и если вы оставите requireоператоры, это может нарушить автоматическую перезагрузку. Больше информации здесь
  3. Устанавливается config.eager_load = trueво всех средах, чтобы с радостью видеть проблемы с загрузкой кода в dev.
  4. Используйте Rails.application.eager_load!перед игрой с потоками, чтобы избежать ошибок "циклической зависимости".
  5. Если у вас есть расширения ruby ​​/ rails, оставьте этот код в старом libкаталоге и загрузите их вручную из инициализатора. Это обеспечит загрузку расширений до того, как ваша дальнейшая логика может от них зависеть:

    # config/initializers/extensions.rb
    Dir["#{Rails.root}/lib/ruby_ext/*.rb"].each { |file| require file }
    Dir["#{Rails.root}/lib/rails_ext/*.rb"].each { |file| require file }
Лев Лукомский
источник
8
Итак, как libтеперь использовать папку? Я имею в виду, что перемещение libdir в appdir похоже на обходной путь.
Мартин Свобода
3
/app/lib/поместил файл / класс, и он НЕ автозагрузился. протестирован в рельсах 5.1, новый проект
Тим Кречмер
29
Стоит отметить, что пружину нужно останавливать. Я переместил все в app / lib /, а затем потратил немного времени на размышления, почему я до сих пор не могу использовать свои классы из консоли.
Spring
1
Куда пойдет следующая строкаRails.application.eager_load!
Стивен Агилар
1
Это может сработать, но это не лучшее решение. Структура папок тоже семантическая. Вещи внутри libвоспринимают близость к проекту иначе, чем вещи в appкаталоге. Некоторые другие ответы лучше этого.
CWitty
84

Я просто использовал config.eager_load_pathsвместо config.autoload_pathsупоминания акостадинов в комментарии на github: https://github.com/rails/rails/issues/13142#issuecomment-275492070

# config.autoload_paths << Rails.root.join('lib')
config.eager_load_paths << Rails.root.join('lib')

Он работает в среде разработки и производства.

Спасибо, Йохан, за предложение заменить #{Rails.root}/libна Rails.root.join('lib')!

Михал Залевский
источник
3
Работает как шарм. Мне не понравился синтаксис, поэтому я изменил его на config.eager_load_paths << Rails.root.join('lib').
3limin4t0r
2
Для меня это был лучший ответ. Мой проект на Rails 5.2 начался с нуля, а папка / lib все еще создавалась вне папки / app. Я не видел веской причины перемещать его.
Самир Хаддад
1
Ага, это работает! Кажется, разработчикам Rails очень нравится вызывать проблемы с загрузкой библиотеки: D До следующего раза!
Дэмиен Рош
config.eager_load_paths += [Rails.root.join('lib')]Вместо этого в Rails 5.2 используется, потому что config.eager_load_pathsэто замороженный массив
Уильям Вонг Гарай,
@WilliamWongGaray config.eager_load_paths доступен только для чтения, когда вы пытаетесь изменить его в инициализаторе. При добавлении путей application.rbон будет работать обоими способами.
Михал Залевский
31

Автозагрузка отключена в производственной среде из-за безопасности потоков. Спасибо @ Зелёный за ссылку.

Я решил эту проблему, сохранив файлы lib в libпапке в моем appкаталоге, как рекомендовано на Github . Каждая папка в appпапке загружается Rails автоматически.

Тобиас
источник
6
Если вы не хотите копаться в длинном обсуждении на Github, вы можете найти подробное объяснение здесь: Collectiveidea.com/blog/archives/2016/07/22/…
Эрнест,
7
Я использовал config.eager_load_paths << "#{Rails.root}/lib", это лучше IMO, чтобы следовать рекомендуемой структуре приложения rails.
Акостадинов 05
2
Включение lib app/libрекомендуется участниками rails github.com/rails/rails/issues/13142#issuecomment-275549669
eXa
4
Это полностью разрушает цель lib. Я бы подождал, пока зазвонит нежная любовь или DHH. А пока я (лично) рекомендую придерживаться ответа @Lev Lukomsky.
Джош Броуди
@JoshBrody Сейчас я считаю, что /libкаталог вам вообще не нужен . Сторонние библиотеки в большинстве случаев представляют собой драгоценные камни, а если нет, то должен быть создан гем. Для других файлов я создаю в /appкаталоге определенные папки . Например validators.
Тобиас
22

Должна быть причина, по которой автозагрузка отключена в производственной среде по умолчанию.

Вот долгая дискуссия по этому поводу. https://github.com/rails/rails/issues/13142

Зелёный
источник
1
Это обсуждение является лучшим, хотя и долгим, источником информации по теме, с которой я столкнулся.
Джейсон
12

Это позволяет иметь автоматическую перезагрузку библиотеки, а также работает в производственной среде.

PS Я изменил свой ответ, теперь он добавляет к обоим путям автозагрузки, независимо от среды, что позволяет работать и в пользовательских средах (например, на сцене)

# config/initializers/load_lib.rb
...
config.eager_load_paths << Rails.root.join('lib')
config.autoload_paths << Rails.root.join('lib')
...
srghma
источник
2
Не могли бы вы подробнее объяснить, почему это решает проблему?
Stuart.Sklinar
@ Stuart.Sklinar, это позволяет автоматически перезагружать библиотеку, а также работает в производственной среде. PS Я изменил свой ответ, теперь он добавляет к обоим желаемым путям автозагрузки, независимо от среды, что позволяет работать и в пользовательских средах (например, stage)
srghma
1
Не могли бы вы расширить (в своем ответе)? Ответ только на код на самом деле никому не помогает понять, почему это должно быть сделано «таким образом» - я должен добавить, что я не разработчик Ruby, просто помогая прояснить SO. Добавление комментария к «ответу только на код» придаст ему некоторый реальный контекст.
Stuart.Sklinar
1
@ Stuart.Sklinar уверен
srghma
6

Просто измените config.autoload_paths на config.eager_load_paths в файле config / application.rb. Потому что в rails 5 автозагрузка по умолчанию отключена для производственной среды. Для получения более подробной информации перейдите по ссылке .

 #config.autoload_paths << "#{Rails.root}/lib"
  config.eager_load_paths << Rails.root.join('lib')

Он работает как для разработки среды, так и для производства.

Джитендра Ратор
источник
4

В некотором смысле, здесь представлен единый подход в Rails 5 для централизации конфигурации готовности и автозагрузки, в то же время он добавляет требуемый путь автозагрузки всякий раз, когда настроена активная загрузка, иначе она не сможет работать правильно:

# config/application.rb
...
config.paths.add Rails.root.join('lib').to_s, eager_load: true

# as an example of autoload only config
config.paths.add Rails.root.join('domainpack').to_s, autoload: true
...
Почепцов
источник
2

Для тех, кто боролся с этим, как я, недостаточно просто разместить каталог app/. Да, вы получите автозагрузку, но не обязательную перезагрузку, которая требует соблюдения соглашений об именах .

Кроме того, использование инициализатора для загрузки старого корневого уровня libпредотвратит перезагрузку во время разработки.

Абдулла Баррак
источник
0

Перемещение папки lib в приложение помогло решить проблему, мой API Twitter не работал в производственной среде. У меня была «неинициализированная константа TwitterApi», и мой Twitter API находился в моей папке lib. У меня был config.autoload_paths += Dir["#{Rails.root}/app/lib"]файл application.rb, но он не работал до перемещения папки.

Это сработало

Laurie
источник
-6

резюмируя ответ Льва: mv lib appбыло достаточно, чтобы все моиlib код был автоматически загружен / перезагружен.

(rails 6.0.0beta3, но должен работать и на rails 5.x)

localhostdotdev
источник