Найкращий спосіб завантажити модуль / клас з папки lib в Rails 3?


273

Оскільки останній реліз 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);

Відповіді:


250

Станом на Rails 2.3.9 є налаштування, в config/application.rbякому ви можете вказати каталоги, які містять файли, які ви хочете завантажити автоматично.

Від application.rb:

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)

7
Примітка @ вдячна відповідь також, якщо ви хочете автоматично завантажити все піддерево app/lib.
— Том Гаррісон

199
# Autoload lib/ folder including all subdirectories
config.autoload_paths += Dir["#{config.root}/lib/**/"]

Джерело: Rails 3 Quicktip: Автозавантажити каталог ліб, включаючи всі підкаталоги, уникайте ледачого завантаження

Зауважте, що файли, що містяться в папці lib, завантажуються лише при запуску сервера. Якщо ви хочете отримати комфорт для автоматичного завантаження цих файлів, прочитайте: Rails 3 Quicktip: Автоматичне завантаження папок lib в режимі розробки . Пам’ятайте, що це не призначено для виробничого середовища, оскільки постійне перезавантаження сповільнює роботу машини.


Посилання мертві
— Бесі

84

Магія автозавантаження матеріалів

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

Тож, коли мова заходить про завантаження матеріалів з підкаталогів, то тут слід знати, чи є умова або умова. Іноді магія Ruby / 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"і це працювало б так само.

PS Я змушений додати ще одну важливу річ. Останнім часом, коли я хочу мати щось у каталозі lib, яке потребує автоматичного завантаження, я схильний починати думати, що якщо це щось, що я насправді розробляю спеціально для цього проекту (який, як правило, є, це може бути якийсь день перетвориться на "статичний" фрагмент коду, який використовується у багатьох проектах, або підмодуль git тощо. У такому випадку він обов'язково повинен бути в папці lib), можливо, його місце взагалі не знаходиться в папці lib. Можливо, це має бути в підпапці під папкою додатків. · У мене є відчуття, що це новий спосіб рейки. Очевидно, та ж магія є в роботі, де б ви не завантажили шляхи автозавантаження, щоб ви вміли вносити свої речі. У всякому разі, це лише мої думки з цього приводу. Ви вільні не погоджуватися. :)


ОНОВЛЕННЯ: Про тип магії ..

Як зазначив Северін у своєму коментарі, ядро ​​"механізм автоматичного завантаження модуля" впевнене, що це частина Ruby, однак шлях автозавантаження не відповідає. Вам не потрібні рейли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/… ). Я помиляюся?
— Северин

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

1
Я витратив півгодини або близько на це, занурюючись. Мені потрібно було (хотілося) для автоматичного завантаження зірочок :: JSRender :: Процесор. Шлях до цього можна знайти, потрапивши в консоль рейлів та виконуючи "Зірочки :: JSRender :: Процесор". Підкреслюючи та зневажаючи, що це "зірочки / js_render / процесор" (з доданим .rb) хтось HTH.
— pedz

Ти щойно врятував мені розум. ~ глибоко зітхнути з полегшенням ~ дякую тобі за поділ :)
— Бренден

Дякую за цей найкорисніший коментар. Я не розумів, чому деякі модулі поводяться так, як вони, поки я не прочитав ваш коментар. Благословення на вас!
— mjnissim

41

Попередження: якщо ви хочете завантажити "патч мавпи" або "відкритий клас" зі своєї папки "lib", не використовуйте підхід "автозавантаження" !!!

  • Підхід " config.autoload_paths ": працює лише в тому випадку, якщо ви завантажуєте клас, визначений лише в одному місці. Якщо якийсь клас уже визначений десь в іншому місці, ви не можете завантажити його знову за допомогою цього підходу.

  • " config / inicijalizer / load_rb_file.rb " підхід: завжди працює! незалежно від того, який цільовий клас є новим класом або "відкритим класом" або "мавпочкою" для існуючого класу, він завжди працює!

Детальніше дивіться на веб-сайті : https://stackoverflow.com/a/6797707/445908


6
Це важлива відмінність для розуміння. Дякую за це
— Тайлер Колліє


18

У моєму випадку я намагався просто завантажити файл прямо під dir lib.

У межах application.rb ...

require '/lib/this_file.rb' 

не працював навіть у консолі, а потім, коли я спробував

require './lib/this_file.rb' 

і рейки прекрасно завантажують файл.

Я все ще досить noob, і я не впевнений, чому це працює, але це працює. Якщо хтось хотів би пояснити це мені, я би вдячний: DI сподіваюся, що це комусь допоможе в будь-якому випадку.


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 не працює для мене. Я вирішую це по-іншому

Рубін на рейках 3 не автоматично перезавантажує (автозавантажує) код із папки / lib. Я вирішую це, поклавши всерединуApplicationController

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

4

Якщо лише до певних файлів потрібен доступ до модулів у lib, просто додайте оператор вимагання до файлів, які потребують цього. Наприклад, якщо одній моделі потрібно отримати доступ до одного модуля, додайте:

require 'mymodule'

вгорі файлу model.rb.


50
Не слід використовувати requireв додатку рейки, тому що це запобігає ActiveSupport::Dependenciesнеправильному завантаженню цього коду. Натомість слід скористатись config.autoload_pathsвідповіддю вище, а потім включити / розширити, якщо потрібно.
— ben_h

13
Дякую @Mike, я збирався зробити те, що ти зробив, було добре побачити пояснення, чому це погано, дякую, що не видалила відповіді.
— pupeno

як щодо включення "mymodule", якщо ви просто хочете завантажити один модуль?
— Майк

1
@ben_h Якщо ви не звідкись requireу додатку Rails? У завданні граблями я зараз require-ing та include-ing модуль, який живе lib/. Чи не повинен я цього робити?
— Денніс

@ben_h Мій пошук виявляє, що це звичайно для requireвашого lib/коду (наприклад, це повідомлення в блозі , ця відповідь ТАК ). Я все ще не впевнений у всьому. Чи можете ви дати більше доказів за позовом про невикористання require?
— Денніс

2

Написати ім'я файлу правильно.

Серйозно. Я боровся з класом протягом години, тому що клас був Управління :: ArchitectureBoard, а файл знаходився в lib / management / architecture_baord.rb (перекладено O та A у "board")

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


2

Наразі Rails 5, рекомендується помістити папку lib під каталог додатків або замість цього створити інші значущі простори імен для папки як services, presentersі featuresт. Д. Та помістити її в каталог додатків для автоматичного завантаження рейлами.

Будь ласка, перевірте також цю дискусійну посилання GitHub .


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