Найкращий спосіб завантажити модуль / клас з папки 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.