Путь автозагрузки и классы вложенных сервисов вылетают в Ruby

У меня несколько проблем с загрузкой /требованием классов в моей папке app/services в проекте Rails 5, и я начинаю давать на этом вопросе.

Прежде всего, чтобы быть понятным, services/ - это простые классы PORO, которые я использую в своем проекте для абстрагирования большей части бизнес-логики от контроллеры, модели и т. д.

Дерево выглядит так

app/
 services/
  my_service/
    base.rb
    funny_name.rb
  my_service.rb  
models/
 funny_name.rb

Ошибка # 1

Сначала, когда я попытался использовать MyService.const_get('FunnyName'), он получил FunnyName из моего каталога моделей. Это не похоже на то же поведение, когда я делаю MyService::FunnyName, хотя в большинстве моих тестов и изменений это работало нормально, это нечетные.

Я понял, что Rails config.autoload_paths не загружает вещи рекурсивно; было бы разумно, чтобы первым FunnyName, которое нужно было отловить, было бы models/funny_name.rb потому что он определенно загружен, но не другой.

Хорошо, давайте найдем обходной путь. Я добавил это в свой application.rb:

config.autoload_paths += Dir[Rails.root.join('app', 'services', '**/')]

Который добавит все подкаталоги служб в config.autoload_paths. Видимо, не рекомендуется писать такие вещи начиная с Rails 5; но эта идея мне подходит.

Ошибка № 2

Теперь, когда я запускаю свое приложение, оно падает и выдает что-то вроде этого

  

Невозможно автоматически загрузить постоянную базу, ожидается   /.../backend/app/services/my_service/base.rb, чтобы определить его (LoadError)

Имена были изменены, но это совпадающий путь от дерева, которое я написал ранее

Дело в том, что base.rb определено в точном файле, который приводит меня к ошибке, которая содержит что-то вроде

class MyService
  class Base
  end
end

Плохое решение

Так что я пробую другой обходной путь, многие из них, ничего не работает. Поэтому я полностью удаляю autoload_paths и добавляю это прямо в application.rb

Dir[Rails.root.join('app', 'services', '**', '*.rb')].each { |file| require file }

Теперь base.rb правильно загружено, MyService.const_get('FunnyName') на самом деле вернет правильный класс, и все работает, но это отвратительный обходной путь. Кроме того, он еще не был протестирован в production, но может создавать проблемы в зависимости от среды.

Запрос целого дерева из application.rb звучит как плохая идея, и я не думаю, что это можно сохранить таким образом.

Какой самый простой способ добавить пользовательский каталог services/ в Rails? Он содержит несколько подкаталогов и классов с простыми именами, которые также присутствуют в других частях приложения (модели, base.rb и т. Д.)

Как избежать путаницы в autoload_paths? Есть ли что-то еще, что я не знаю, что могло бы помочь? Почему base.rb здесь даже вылетает?

4 голоса | спросил Laurent 28 J000000Saturday18 2018, 03:10:32

3 ответа


0
Рабочий растворПосле более глубокого изучения и попыток, я понял, что мне нужно ---- +: = 0 =: + ---- сервисы, чтобы избежать получения неправильных констант при вызове мета-функций, таких как ---- +: = 1 =:+ ---- .Но вот в чем дело: классический ---- +: = 2 =: + ---- не будет работать, потому что по какой-то причине эти классы, очевидно, будут загружены до инициализации всего ядра Rails и простых имен классовтакие как ---- +: = 3 =: + ---- будут фактически перепутаны с ядром, поэтому выведите все из строя.Некоторые могут сказать «затем переименовать Base во что-то другое», но я должен изменить имя класса, заключенное в пространство имен, потому что Rails говорит мне об этом?Я так не думаю.Имена классов должны быть простыми, и то, что я делаю внутри собственного пространства имен, не касается Rails.Я должен был обдумать это и записать свой собственный хук конфигурации Rails.Мы загружаем ядро ​​и все его функциональные возможности, а затем ---- +: = 4 =: + ---- рекурсивно.Кстати, это не добавит веса производственной среде и очень удобно для разработки.Код для добавленияПоместите это в ---- +: = 5 =: + ---- и во все другие среды, которые вы хотите загружать без конфликтов классов Rails (например, ---- +: = 6 =: + ---- вмое дело)Затем создайте новый файл ---- +: = 8 =: + ----, содержащий этоРаботает как шарм.Вы также можете изменить ---- +: = 10 =: + ---- на ---- +: = 11 =: + ----, если вам это нужно.
ответил Laurent 31 J000000Tuesday18 2018, 16:09:17
0
Когда я делаю это (что есть во всех моих проектах), это выглядит примерно так:Я поместил все общие определения методов в ---- +: = 1 =: + ---- :приложение /услуги /service_base.rbЯ ставлю любые методы, общие для ---- +: = 3 =: + ---- в ---- +: = 4 =: + ---- :приложение /услуги /sub_service /service_base.rbА потом любые уникальные методы в ---- +: = 6 =: + ---- :приложение /услуги /sub_service /useful_service.rbЗатем я могу сделать что-то вроде:
ответил jvillian 28 J000000Saturday18 2018, 03:54:57
0
С твоим деревом,services /my_class /base.rb должен выглядеть примерно так:services /my_class /funny_name.rb должен выглядеть примерно так:services /my_class.rb должен выглядеть примерно так:models /funny_name.rb должен выглядеть примерно так:Я говорю «должно выглядеть похоже», потому что класс /модуль взаимозаменяемы;Rails просто ищет эти константы, которые будут определены в этих местах.Вам не нужно ничего добавлять к пути автозагрузки.Rails автоматически подхватывает все в ---- +: = 5 =: + ----Анекдот: в вашем каталоге сервисов довольно обычно трактовать соглашение об именах (как имя файла, так и основную константу) как «_service.rb» или «ThingService» - так же, как выглядят контроллеры.Модели не получают этот суффикс, потому что они рассматриваются как первоклассные объекты.GitLab имеет отличную файловую структуру, на которую стоит обратить внимание.https://gitlab.com/gitlab-org/gitlab-ce
ответил Josh Brody 28 J000000Saturday18 2018, 04:01:30

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132