Автоматичне завантаження файлів lib в Rails 4


229

Я використовую наступний рядок в ініціалізаторі для автоматичного завантаження коду в моєму /lib каталозі під час розробки:

config / ініціалізатори / custom.rb:

RELOAD_LIBS = Dir[Rails.root + 'lib/**/*.rb'] if Rails.env.development?

Rails 3 Quicktip: Автоматичне перезавантаження папок lib в режимі розробки )

Це чудово, але це занадто неефективно для використання у виробництві. Замість того, щоб завантажувати ваги на кожен запит, я просто хочу завантажити їх під час запуску. У тому ж блозі є ще одна стаття, що описує, як це зробити:

config / application.rb:

# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]

Однак, коли я переходжу на це, навіть у процесі розвитку, я отримую NoMethodErrors при спробі використання функцій lib.

Приклад одного з моїх файлів lib:

lib / extensions.rb:

Time.class_eval do
  def self.milli_stamp
    Time.now.strftime('%Y%m%d%H%M%S%L').to_i
  end
end

Виклик Time.milli_stampкине NoMethodError

Я усвідомлюю, що інші відповіли на подібні запитання щодо ТА, але всі вони, мабуть, мають справу з умовами іменування та іншими питаннями, про які раніше мені не довелося переживати. Мої класи ліб вже працювали для завантаження за запитом, я просто хочу це змінити для початку завантаження. Який правильний спосіб зробити це?


Чи папка config / ініціалізаторів автоматично завантажується при запуску програми Rails?
Jwan622

Відповіді:


548

Я думаю, що це може вирішити вашу проблему:

  1. у config / application.rb :

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

    і зберігати правильну конвенцію про іменування в lib .

    в lib / foo.rb :

    class Foo
    end

    в lib / foo / bar.rb :

    class Foo::Bar
    end
  2. якщо ви дійсно хочете зробити кілька патчів мавпи у файлі, як lib / extensions.rb , ви можете вручну вимагати цього:

    у config / inicijalizer / requ.rb :

    require "#{Rails.root}/lib/extensions" 

PS


1
@ ifyouseewendy- Ви абсолютно праві, тому що extensions.rb не дотримувався конвенцій про іменування Rails, Rails не включив його в процес завантаження. Я змусив це працювати, вимагаючи його вручну.
Ярін

@ifyouseewendy Як я можу включати файли перед завантаженням моделей? додати шлях до автоматичного завантаження це круто, але як контролювати порядок включення? thx
Матриця

@Matrix "включати файли перед завантаженням моделей", ви можете вручну вимагати файл без використання функції автозавантаження.
ifyouseewendy

@ifyouseewendy, якщо я вимагаю його в ініціалізаторі, але файл знаходиться в autoload_path, він буде перезавантажений (завантажений 2 рази) чи ні? theire - це "Requ_once", як у php?
Матриця

5
Схоже, це не працює в API Rails 5 у виробництві (але в розробці). Я вважаю, що вам потрібно користуватися config.eager_load_paths << Rails.root.join('lib'). Однак це має головний недолік у тому, що eager_load_pathsзавантажує все і в завданнях. Я думаю, що рішення лулалали краще. Ось запис у блозі з більш детальною інформацією: blog.arkency.com/2014/11/…
hirowatari

33

Хоча це не відповідає прямо на питання, але я думаю, що це гарна альтернатива взагалі уникнути питання.

Щоб уникнути всіх проблем autoload_pathsчи eager_load_pathsпроблем, створіть каталог "lib" або "misc" у каталозі "app". Розміщуйте коди, як зазвичай це робиться, і Rails завантажує файли так само, як вони завантажуватимуть (і перезавантажуватимуть) файли моделей.


3
Я в Rails 4.2. і він не завантажує автоматично файли appвнизу, мені потрібно це зробити вручну ...... або потрібно помістити його в шлях автозавантаження ..
Arup Rakshit

6
Ви помиляєтесь, Arup, будь-які підкаталоги каталогів додатків автоматично знаходяться в масиві autoload_paths в Rails 4.2. Дивіться edgeguides.rubyonrails.org/…
Dr.Strangelove

За винятком app/viewsкаталогу, який не додається; а точніше видаляється явно.
Джеймс Б. Берн

1
Чудова відповідь. Єдине, що працювало для мене на рейках 5 / api.
jstafford

6
Пам'ятайте, що libвін призначений для коду, який може застосовуватися до декількох проектів і, можливо, може бути витягнутий до дорогоцінного каміння. Якщо не створити більш відповідну папку під час пошуку додатків як services/або presenters/і навіть підкаталог.
PhilT

6

Це може допомогти комусь, як я, що знаходить цю відповідь під час пошуку рішень щодо того, як Rails обробляє завантаження класу ... Я виявив, що мені потрібно було визначити moduleім'я, яке відповідає моєму файлу належним чином, а не просто визначати клас:

У файлі lib / development_mail_interceptor.rb (Так, я використовую код з Railscast :))

module DevelopmentMailInterceptor
  class DevelopmentMailInterceptor
    def self.delivering_email(message)
      message.subject = "intercepted for: #{message.to} #{message.subject}"
      message.to = "myemail@mydomain.org"
    end
  end
end

працює, але не завантажується, якби я не клав клас всередину модуля.


1
У рубіні "відповідна відповідність" означає, що файл розташований у файловій системі за адресою LOAD_PATH/module/class.rb(підкреслено), де LOAD_PATHзнаходиться на шляхах завантаження, використовуваних додатком Ruby (autoload_paths у випадку Rails). libколивався від автоматичного завантаження Rails до не завантаження, а в останніх версіях (> = Rails 3.x) він не завантажується автоматично. Яка б магія не робила цю роботу для вас не рекомендується. Можливо, це старий Railscast?
Пітер Х. Боллінг

0

Використовуйте config.to_prepare для завантаження виправлень / розширень мавп для кожного запиту в режимі розробки.

config.to_prepare do |action_dispatcher|
 # More importantly, will run upon every request in development, but only once (during boot-up) in production and test.
 Rails.logger.info "\n--- Loading extensions for #{self.class} "
 Dir.glob("#{Rails.root}/lib/extensions/**/*.rb").sort.each do |entry|
   Rails.logger.info "Loading extension(s): #{entry}"
   require_dependency "#{entry}"
 end
 Rails.logger.info "--- Loaded extensions for #{self.class}\n"

кінець

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.