Rails 5: Załaduj pliki lib w środowisku produkcyjnym

132

Zaktualizowałem jedną z moich aplikacji z Rails 4.2.6 do Rails 5.0.0. Upgrade Przewodnik mówi, że funkcja Autoload jest teraz wyłączone w produkcji domyślnie.

Teraz zawsze pojawia się błąd na moim serwerze produkcyjnym, ponieważ ładuję wszystkie pliki lib z automatycznym ładowaniem w application.rbpliku.

module MyApp
    class Application < Rails::Application
        config.autoload_paths += %W( lib/ )
    end
end

Na razie mam ustawić config.enable_dependency_loadingaby trueale zastanawiam się, czy istnieje lepsze rozwiązanie tego. Musi istnieć powód, dla którego automatyczne ładowanie jest domyślnie wyłączone w środowisku produkcyjnym.

Tobias
źródło
szalona rzecz, a dokumenty nadal mówią ci, żebyś wykonywał auto_load. Byłem bardzo zdezorientowany, co jest nie tak w środowisku produkcyjnym nowej aplikacji. Odkąd zacząłem uczyć się z Railsami 5, nie przeczytałem przewodnika po migracji. Mam nadzieję, że zgłosiłem
akostadinov
1
o dziwo, mam dwa pliki w libdir, jeden plik jest łatwo dostępny w Runtime, ale inny musi być wymagany ręcznie: D
iluzjonista
@Tobias Jakie rozwiązanie znalazłeś?
geoboy
@geoboy I kod grupy (jak Validators) w folderach bezpośrednio w katalogu aplikacji /, ponieważ kod jest ładowany automatycznie.
Tobias,
chodzi o właściwą ścieżkę pliku i definicji klasy Oto, co działa na mnie w Rails 5.2: ścieżka pliku: app/services/paylinx/paylinx_service.rbdefinicja klasy: module Paylinx class PaylinxService end end. Próbowałem tych autoload_pathsrzeczy. nie działa dla mnie.
NamNamNam

Odpowiedzi:

163

Moja lista zmian po przejściu na Rails 5:

  1. Umieść libdir w, appponieważ cały kod wewnątrz aplikacji jest automatycznie ładowany w wersji deweloperskiej i chętnie ładowany w wersji produkcyjnej, a co najważniejsze jest automatycznie ładowany podczas programowania, więc nie musisz ponownie uruchamiać serwera za każdym razem, gdy wprowadzasz zmiany.
  2. Usuń wszystkie requireinstrukcje wskazujące na twoje własne klasy wewnątrz, libponieważ i tak są one automatycznie ładowane, jeśli ich nazewnictwo plików / katalogów jest poprawne, a jeśli zostawisz requireinstrukcje, może to przerwać automatyczne ładowanie. Więcej informacji tutaj
  3. Ustaw config.eager_load = truewe wszystkich środowiskach, aby zobaczyć problemy z ładowaniem kodu w dev.
  4. Użyj Rails.application.eager_load!przed rozpoczęciem gry z wątkami, aby uniknąć błędów „zależności cyklicznych”.
  5. Jeśli masz jakieś rozszerzenia ruby ​​/ rails, zostaw ten kod w starym libkatalogu i załaduj je ręcznie z inicjatora. Zapewni to, że rozszerzenia zostaną załadowane przed dalszą logiką, która może na nim polegać:

    # config/initializers/extensions.rb
    Dir["#{Rails.root}/lib/ruby_ext/*.rb"].each { |file| require file }
    Dir["#{Rails.root}/lib/rails_ext/*.rb"].each { |file| require file }
    
Lev Lukomsky
źródło
8
Jak więc libteraz używa się folderu? Chodzi mi o to, że przeniesienie libdir do appdir wydaje się być obejściem.
Martin Svoboda
3
/app/lib/umieścił plik / klasę i NIE ładuje się automatycznie. testowany na szynach 5.1, nowy projekt
Tim Kretschmer
31
Warto zauważyć, że musisz zatrzymać wiosnę. Przeniosłem wszystko do app / lib /, a potem zmarnowałem trochę czasu, zastanawiając się, dlaczego nadal nie mogę używać moich zajęć z konsoli. przystanek wiosenny ftw :)
jacklin
1
Gdzie poszłaby następująca liniaRails.application.eager_load!
Steven Aguilar
1
To może działać, ale nie jest to najlepsze rozwiązanie. Struktura folderów jest również semantyczna. Rzeczy w katalogu libmają inną postrzeganą bliskość do projektu niż rzeczy w appkatalogu. Kilka innych odpowiedzi jest lepszych niż ta.
CWitty
87

Po prostu użyłem config.eager_load_pathszamiast config.autoload_pathsjak wspomnieć akostadinov w komentarzu na github: https://github.com/rails/rails/issues/13142#issuecomment-275492070

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

Działa na środowisku deweloperskim i produkcyjnym.

Dzięki Johan dla propozycja zastąpienia #{Rails.root}/libz Rails.root.join('lib')!

Michał Zalewski
źródło
3
Działa jak marzenie. Nie podobała mi się składnia, więc zmieniłem ją na config.eager_load_paths << Rails.root.join('lib').
3limin4t0r
2
Dla mnie to była najlepsza odpowiedź. Mój projekt rozpoczął się na Railsach 5.2 od zera, a folder / lib nadal był tworzony poza folderem / app. Nie widziałem dobrego powodu, aby go przenieść.
Samir Haddad
1
Tak, to działa! Wygląda na to, że deweloperzy Railsów naprawdę lubią powodować problemy z ładowaniem lib: D do następnego razu!
Damien Roche
1
To Rails 5.2 używa config.eager_load_paths += [Rails.root.join('lib')]zamiast tego, ponieważ config.eager_load_pathsjest zamrożoną tablicą
William Wong Garay
@WilliamWongGaray config.eager_load_paths jest tylko do odczytu, gdy próbujesz zmodyfikować go w inicjatorze. Po dodaniu ścieżek application.rbbędzie działać przy użyciu obu metod.
Michał Zalewski
32

Automatyczne ładowanie jest wyłączone w środowisku produkcyjnym ze względu na bezpieczeństwo wątków. Dziękuję @ Зелёный za link.

Rozwiązałem ten problem, przechowując pliki lib w libfolderze w moim appkatalogu, zgodnie z zaleceniami na Github . Każdy folder w appfolderze jest automatycznie ładowany przez Railsy.

Tobias
źródło
6
Jeśli nie chcesz przekopywać się przez długi wątek dyskusyjny na Github, możesz znaleźć destylowane wyjaśnienie tutaj: collectidea.com/blog/archives/2016/07/22/…
Ernest
7
Użyłem config.eager_load_paths << "#{Rails.root}/lib", to lepsze IMO, aby podążać za zalecaną strukturą aplikacji rails.
akostadinov
2
Włączenie lib app/libjest zalecane przez członków rails github.com/rails/rails/issues/13142#issuecomment-275549669
eXa
4
To całkowicie rujnuje cel lib. Czekałbym, aż tuczna miłość lub DHH się włączy. W międzyczasie (osobiście) radziłbym trzymać się odpowiedzi @Lev Lukomsky.
Josh Brody,
@JoshBrody Moja opinia jest taka, że ​​w ogóle nie powinieneś potrzebować /libkatalogu. Biblioteki stron trzecich są w większości klejnotami, a jeśli nie, powinny zostać utworzone. Dla innych plików tworzę określone foldery w /appkatalogu. Na przykład validators.
Tobias
22

Musi istnieć powód, dla którego automatyczne ładowanie jest domyślnie wyłączone w środowisku produkcyjnym.

Oto długa dyskusja na ten temat. https://github.com/rails/rails/issues/13142

Зелёный
źródło
1
Ta dyskusja jest najlepszym, choć obszernym, źródłem informacji na temat, z jakim się spotkałem.
Jason
12

Pozwala to na automatyczne ładowanie lib i działa również w środowisku produkcyjnym.

PS Zmieniłem odpowiedź, teraz dodaje się do obu chętnych - automatyczne ładowanie ścieżek, niezależnie od środowiska, aby umożliwić pracę również w niestandardowych środowiskach (takich jak stage)

# config/initializers/load_lib.rb
...
config.eager_load_paths << Rails.root.join('lib')
config.autoload_paths << Rails.root.join('lib')
...
srghma
źródło
2
Czy mógłbyś wyjaśnić, dlaczego to rozwiązuje problem?
Stuart.Sklinar
@ Stuart.Sklinar pozwala to na automatyczne ładowanie biblioteki lib i działa również w środowisku produkcyjnym. PS Zmieniłem odpowiedź, teraz dodaje się do obu chętnych - automatyczne ładowanie ścieżek, niezależnie od środowiska, aby umożliwić pracę również w niestandardowych środowiskach (takich jak scena)
srghma
1
Czy mógłbyś rozwinąć (w swojej odpowiedzi)? Tylko kod odpowiedzi tak naprawdę nikomu nie pomagają zrozumieć, dlaczego powinno się to robić „w ten sposób” - powinienem dodać, że nie jestem programistą Ruby, tylko pomagam wyjaśnić SO. Dodanie komentarza do odpowiedzi „tylko kod” nadałoby jej rzeczywisty kontekst.
Stuart.Sklinar
1
@ Stuart.Sklinar sure
srghma
7

Po prostu zmień config.autoload_paths na config.eager_load_paths w pliku config / application.rb. Ponieważ w rails 5 automatyczne ładowanie jest domyślnie wyłączone dla środowiska produkcyjnego. Aby uzyskać więcej informacji, kliknij łącze .

 #config.autoload_paths << "#{Rails.root}/lib"
  config.eager_load_paths << Rails.root.join('lib')

Działa zarówno na potrzeby rozwoju środowiska, jak i produkcji.

Jitendra Rathor
źródło
5

W pewnym sensie tutaj jest ujednolicone podejście w Railsach 5 do scentralizowania konfiguracji przyspieszonego i automatycznego ładowania, jednocześnie dodaje wymaganą ścieżkę automatycznego ładowania, gdy zostanie skonfigurowane pożądane ładowanie, w przeciwnym razie nie będzie w stanie działać poprawnie:

# config/application.rb
...
config.paths.add Rails.root.join('lib').to_s, eager_load: true

# as an example of autoload only config
config.paths.add Rails.root.join('domainpack').to_s, autoload: true
...
pocheptsov
źródło
2

Dla każdego, kto zmagał się z tym, tak jak ja, nie wystarczy po prostu umieścić katalog pod app/. Tak, otrzymasz automatyczne ładowanie, ale nie będzie to konieczne ponowne ładowanie, co wymaga przestrzegania konwencji przestrzeni nazw .

Ponadto użycie inicjalizatora do ładowania starego poziomu roota libzapobiegnie przeładowaniu funkcji podczas programowania.

Abdullah Barrak
źródło
0

Przeniesienie folderu lib do aplikacji pomogło rozwiązać problem, mój interfejs API na Twitterze nie działał w środowisku produkcyjnym. Miałem „niezainicjowaną stałą TwitterApi”, a moje API Twittera znajdowało się w folderze lib. Miałem config.autoload_paths += Dir["#{Rails.root}/app/lib"]plik application.rb, ale nie działał przed przeniesieniem folderu.

To załatwiło sprawę

Laurie
źródło
-6

podsumowując odpowiedź Lwa: mv lib appwystarczyło, aby cały mój libkod był automatycznie ładowany / ponownie ładowany.

(szyny 6.0.0beta3, ale powinny działać dobrze również na szynach 5.x)

localhostdotdev
źródło