Najlepszy sposób załadowania modułu / klasy z folderu lib w Rails 3?

273

Ponieważ najnowsze wydanie Rails 3 nie obsługuje już modułów i klas z biblioteki lib, jaki byłby najlepszy sposób na ich załadowanie?

Z 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);
Vincent
źródło

Odpowiedzi:

250

Począwszy od wersji 2.3.9 Railsów , istnieje ustawienie, config/application.rbw którym można określić katalogi zawierające pliki, które mają być ładowane automatycznie.

Z application.rb:

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
Slobodan Kovacevic
źródło
7
Uwaga @ odpowiedź wdzięczna również, jeśli chcesz automatycznie załadować całe poddrzewo app/lib.
Tom Harrison
199
# Autoload lib/ folder including all subdirectories
config.autoload_paths += Dir["#{config.root}/lib/**/"]

Źródło: Rails 3 Skrócona wskazówka: automatycznie ładuj katalog lib zawierający wszystkie podkatalogi, unikaj leniwego ładowania

Pamiętaj, że pliki zawarte w folderze lib są ładowane tylko podczas uruchamiania serwera. Jeśli chcesz komfortowo automatycznie ładować te pliki, przeczytaj: Rails 3 Quicktip: Automatyczne ładowanie folderów lib w trybie programowania . Należy pamiętać, że nie jest to przeznaczone dla środowiska produkcyjnego, ponieważ stałe przeładowanie spowalnia maszynę.

wdzięczny
źródło
Linki są martwe
Besi
84

Magia automatycznego ładowania rzeczy

Myślę, że opcja kontrolowania folderów, z których odbywa się automatyczne ładowanie, została wystarczająco opisana w innych odpowiedziach. Jednak w przypadku, gdy ktoś inny ma problemy z załadowaniem rzeczy, mimo że zmodyfikowano ich ścieżki automatycznego ładowania zgodnie z wymaganiami, odpowiedź ta próbuje wyjaśnić, na czym polega magia tego ładowania automatycznego.

Więc jeśli chodzi o ładowanie rzeczy z podkatalogów, musisz mieć gotcha lub konwencję, o której powinieneś wiedzieć. Czasami magia Ruby / Rails (tym razem głównie Rails) może utrudnić zrozumienie, dlaczego coś się dzieje. Każdy moduł zadeklarowany w ścieżkach automatycznego ładowania zostanie załadowany tylko wtedy, gdy nazwa modułu odpowiada nazwie katalogu nadrzędnego. Na wypadek, gdybyś spróbował wprowadzić lib/my_stuff/bar.rbcoś takiego:

module Foo
  class Bar
  end
end

Nie zostanie załadowany automatycznie. Potem znowu, jeśli zmiana nazwy nadrzędnej dir aby foow ten sposób gospodarzem modułu w ścieżce: lib/foo/bar.rb. Będzie tam dla ciebie. Inną opcją jest nadanie nazwy pliku, który chcesz automatycznie załadować, według nazwy modułu. Oczywiście wtedy może istnieć tylko jeden plik o tej nazwie. Jeśli chcesz podzielić swoje pliki na wiele plików, możesz oczywiście użyć tego jednego pliku, aby wymagać innych plików, ale nie polecam tego, ponieważ wtedy, gdy jesteś w trybie programowania i modyfikujesz te inne pliki, Rails nie jest w stanie automagicznie przeładuj je dla ciebie. Ale jeśli naprawdę chcesz, możesz mieć jeden plik według nazwy modułu, który określa rzeczywiste pliki wymagane do korzystania z modułu. Więc możesz mieć dwa pliki: lib/my_stuff/bar.rbi lib/my_stuff/foo.rbten pierwszy jest taki sam jak powyżej, a drugi zawiera jedną linię:require "bar"i to działałoby tak samo.

PS Czuję się zmuszony dodać jeszcze jedną ważną rzecz. Ostatnio, kiedy chcę mieć coś w katalogu lib, który wymaga automatycznego załadowania, zaczynam myśleć, że jeśli jest to coś, co faktycznie opracowuję specjalnie dla tego projektu (co zwykle jest, może to pewnego dnia zamienia się w „statyczny” fragment kodu używany w wielu projektach lub podmoduł git itp., w którym to przypadku zdecydowanie powinien znajdować się w folderze lib), być może jego miejsce w ogóle nie znajduje się w folderze lib. Być może powinien on znajdować się w podfolderze w folderze aplikacji · Mam wrażenie, że jest to nowy sposób robienia rzeczy. Oczywiście, ta sama magia działa wszędzie tam, gdzie w tobie są ładowane ścieżki, w które wkładasz swoje rzeczy, więc dobrze jest z tymi rzeczami. W każdym razie to tylko moje przemyślenia na ten temat. Możesz się nie zgodzić. :)


AKTUALIZACJA: O rodzaju magii ..

Jak zauważył Severin w swoim komentarzu, rdzeń „autoload a module module” z pewnością jest częścią Ruby, ale ścieżki autoload nie są. Nie potrzebujesz do tego Railsówautoload :Foo, File.join(Rails.root, "lib", "my_stuff", "bar"). A kiedy spróbujesz po raz pierwszy odwołać się do modułu Foo, zostanie on dla Ciebie załadowany. Jednak to, co robi Rails, to sposób na automatyczne ładowanie rzeczy z zarejestrowanych folderów, co zostało zaimplementowane w taki sposób, że musi on założyć coś o konwencjach nazewnictwa. Jeśli nie został tak zaimplementowany, to za każdym razem, gdy odwołujesz się do czegoś, co nie jest aktualnie załadowane, musiałby przejść przez wszystkie pliki we wszystkich folderach automatycznego ładowania i sprawdzić, czy którykolwiek z nich zawiera to, co próbujesz odwołać. To z kolei podważyłoby ideę automatycznego ładowania i automatycznego ładowania. Jednak dzięki tym konwencjom można odjąć od modułu / klasy, którą próbujesz załadować tam, gdzie można to zdefiniować, i po prostu załadować.

Timo
źródło
1
Dlaczego ta magia Ruby? Ruby zapewnia tylko funkcję automatycznego ładowania modułu #, której można użyć do polecenia ładowania pliku podczas uzyskiwania dostępu do (niezdefiniowanej) stałej (patrz ruby-doc.org/core-1.9.3/Module.html#method-i-autoload ). Moim zdaniem dopasowanie nazw modułów / klas do katalogów / plików odbywa się w Rails / ActiveSupport (np. Tutaj: github.com/rails/rails/blob/… ). Czy się mylę?
severin
Tak, uważam, że masz rację. Byłem zbyt pochopny, aby „skorygować” moją pierwotną odpowiedź, kiedy Zabba wskazał jej „wadę”. Pozwól, że zaktualizuję nieco moją odpowiedź, aby wyjaśnić ten problem.
Timo,
1
Spędziłem około pół godziny. Potrzebowałem (chciałem) automatycznie załadować zębatki :: JSRender :: Processor. Ścieżkę do tego można znaleźć, wchodząc do konsoli szyn i robiąc „Sprockets :: JSRender :: Processor” .underscore i ignorując, że jest to „sprockets / js_render / Processor” (z dodanym .rb) HTH ktoś.
pedz
Właśnie uratowałeś moje zdrowie psychiczne. ~ głębokie westchnienie ulgi ~ bardzo dziękuję za udostępnienie :)
Brenden
Dziękuję za ten najbardziej pomocny komentarz. Nie zrozumiałem, dlaczego niektóre moduły zachowują się tak, jak one, dopóki nie przeczytam twojego komentarza. Błogosławieństwa dla ciebie!
mjnissim
41

Ostrzeżenie: jeśli chcesz załadować „łatkę małpy” lub „klasę otwartą” z folderu „lib”, nie używaj podejścia „autoload” !!!

  • Podejście „ config.autoload_paths ”: działa tylko wtedy, gdy ładujesz klasę zdefiniowaną tylko w JEDNYM miejscu. Jeśli jakaś klasa została już zdefiniowana gdzieś indziej, nie można załadować jej ponownie dzięki temu podejściu.

  • Podejście „ config / initializer / load_rb_file.rb ”: zawsze działa! cokolwiek klasa docelowa jest nową klasą lub „klasą otwartą” lub „małpą łatką” dla istniejących klas, zawsze działa!

Aby uzyskać więcej informacji, zobacz: https://stackoverflow.com/a/6797707/445908

Siwei Shen 申思维
źródło
6
Jest to krytyczne rozróżnienie do zrozumienia. Dzięki za to.
Tyler Collier
28

Bardzo podobne, ale myślę, że jest to trochę bardziej eleganckie:

config.autoload_paths += Dir["#{config.root}/lib", "#{config.root}/lib/**/"]
Brian Armstrong
źródło
18

W moim przypadku próbowałem po prostu załadować plik bezpośrednio do katalogu lib.

W ramach application.rb ...

require '/lib/this_file.rb' 

nie działał, nawet w konsoli, a potem, kiedy próbowałem

require './lib/this_file.rb' 

a szyny ładują plik idealnie.

Nadal jestem dość noob i nie jestem pewien, dlaczego to działa, ale działa. Jeśli ktoś chciałby mi to wyjaśnić, byłbym wdzięczny: mam nadzieję, że to komuś pomoże.

Nick Res
źródło
2
Dzieje się tak, ponieważ ./lib/this_file.rb szuka w bieżącym katalogu (w konsoli Rails, to byłby Twój root Rails), a /lib/this_file.rb szuka tego jako ścieżki bezwzględnej. Przykład: ./lib/this_file.rb = /var/www/myrailsapp/lib/this_file.rb, /lib/this_file.rb = /lib/this_file.rb
Jason
7

Miałem ten sam problem. Oto jak to rozwiązałem. Rozwiązanie ładuje katalog lib i wszystkie podkatalogi (nie tylko bezpośrednie). Oczywiście możesz użyć tego dla wszystkich katalogów.

# application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
hjuskewycz
źródło
5
Ma to nieprzyjemny efekt uboczny polegający na całkowitym zatłoczeniu konwencji przestrzeni nazw Railsów. Jeśli lib / bar / foo.rb definiujący Bar :: Foo pojawi się przed lib / foo.rb definiujący Foo w wyszukiwaniu autoload, wówczas Expected lib/bar/foo.rb to define constant Foowystąpią mylące błędy, takie jak próba załadowania lib / foo.rb poprzez odwołanie się do Foo stały.
Jacob
5

config.autoload_paths nie działa dla mnie. Rozwiązuję to w inny sposób

Ruby on rails 3 nie automatycznie ładuje kodu (autoload) z folderu / lib. Rozwiązuję to, wkładając do środkaApplicationController

Dir["lib/**/*.rb"].each do |path|
  require_dependency path
end 
msa.im
źródło
4

Jeśli tylko niektóre pliki potrzebują dostępu do modułów w bibliotece lib, wystarczy dodać instrukcję wymagającą do plików, które tego potrzebują. Na przykład jeśli jeden model wymaga dostępu do jednego modułu, dodaj:

require 'mymodule'

u góry pliku model.rb.

Mike Fischer
źródło
50
Nie powinieneś używać requirew aplikacji railsowej, ponieważ uniemożliwia ona ActiveSupport::Dependenciesprawidłowe [rozładowanie] tego kodu. Zamiast tego należy użyć config.autoload_pathspowyższej odpowiedzi, a następnie dołączyć / rozszerzyć zgodnie z wymaganiami.
ben_h
13
Dziękuję @Mike, miałem zamiar zrobić to, co zrobiłeś, dobrze było zobaczyć wyjaśnienie, dlaczego jest źle, dziękuję, że nie usunąłeś odpowiedzi.
pupeno
co powiesz na „mymoduł”, jeśli chcesz tylko załadować jeden moduł?
Mike
1
@ben_h Czy nie należy requirenigdzie w aplikacji Rails? W zadaniu natarcia Jestem obecnie require-ing i include-ing moduł, który mieszka w lib/. Nie powinienem tego robić?
Dennis
@ben_h Moje wyszukiwanie ujawnia, że ​​jest on wspólny dla requiretwojego lib/kodu (np. ten post na blogu , ta odpowiedź SO ). Nadal nie jestem pewien co do tego. Czy możesz podać więcej dowodów uzasadniających roszczenie za nieużywanie require?
Dennis
2

Przeliteruj nazwę pliku poprawnie.

Poważnie. Walczyłem z klasą przez godzinę, ponieważ klasą była Governance :: ArchitectureBoard, a plik znajdował się w lib / governance / architecture_baord.rb (transponowane O i A w „tablicy”)

Z perspektywy czasu wydaje się to oczywiste, ale diabeł go śledził. Jeśli klasa nie jest zdefiniowana w pliku, w którym Rails oczekuje, że będzie w oparciu o mungowanie nazwy klasy, po prostu jej nie znajdzie.

David Hempy
źródło
2

Na dzień Rails 5, zaleca się umieścić w folderze lib w katalogu aplikacji lub zamiast tworzyć inne przestrzenie znaczącą nazwę dla folderu jako services, presenters, featuresetc i umieścić go w katalogu aplikacji do automatycznego załadunku przez szyny.

Sprawdź również ten link do dyskusji w serwisie GitHub .

Ashik Salman
źródło