• Odkrywaj. Ucz się. Rozwijaj się. Sieć medialna Fastlane

  • handel elektronicznyFastlane
  • PODSzybki pas
  • SEOfastlane
  • Doradca Fastlane
  • TheFastlaneInsider

9 wskazówek i trików, które pomogą Ci włączyć autoloader Zeitwerk w Twojej aplikacji Rails

9 wskazówek i trików, które pomogą Ci włączyć autoloader Zeitwerk w aplikacji Rails

współautor: Sanket Patel



Wprowadzenie

Masz aplikację Rails 5 (lub starszą) korzystającą z Sidekiq i chcesz zaktualizować ją do najnowszej i najlepszej wersji? Jeśli tak, zostań z nami, aby zapoznać się z kilkoma przydatnymi wskazówkami i trikami, które odkryliśmy podczas tej samej sytuacji. Mamy nadzieję, że pomogą Ci zaoszczędzić czas podczas aktualizacji.

W Rewind szeroko wykorzystujemy Sidekiq 5 w naszych aplikacje do tworzenia kopii zapasowych i kopiowania zadania asynchroniczne.

Używamy silnika Rails zamontowanego w aplikacji Rails, która obsługuje Sidekiq. Silnik zawiera wszystkich pracowników i inną logikę biznesową. Wygląda to mniej więcej tak:

pracownicy i inna logika biznesowa

Podczas aktualizacji z Rails 5 do 6 odkryliśmy, że nasze gemy i silnik Rails zawierały kod niezgodny z nowym domyślnym autoloaderem o nazwie Zeitwerk, przez co serwery aplikacji nie uruchamiały się. Dowiedzieliśmy się również, że Sidekiq 6 wymaga automatycznego ładowania Zeitwerk i nie będzie działać w trybie klasycznym.

Aktualizacja głównej wersji biblioteki innej firmy budzi pewien niepokój. Dodanie fundamentalnej zmiany w sposobie ładowania i odczytywania klas przez aplikację? Auć.

Zespół zdecydował się obejść ten problem, przywracając klasyczny autoloader i pozostawiając Sidekiq w wersji 5.

Mimo wszystko minął prawie rok od wydania Sidekiq 6 i aktualizacja była konieczna już dawno.

Do tej pory wydano wersję Sidekiq 6.1, która zawierała szereg poprawek bezpieczeństwa, błędów i udoskonaleń, które miały na celu ulepszenie naszej usługi – potrzebne aby dowiedzieć się, jak to będzie wyglądać na naszej platformie.

W klasycznym stylu Rewind wygospodarowaliśmy trochę czasu i opracowaliśmy plan mający na celu ograniczenie promienia rażenia ulepszenia.

Oto 9 wskazówek i trików, które powinieneś znać, zanim zaczniesz samodzielnie przeprowadzać aktualizację:

1) zeitwerk:check jest twoim przyjacielem

Gem zeitwerk jest częścią Rails 6 i zawiera przydatne narzędzie sprawdzające, które skanuje folder projektu i próbuje załadować się w trybie przyspieszonym, tak jak aplikacja uruchamia się podczas uruchamiania. Znaleźliśmy dwa sposoby jego użycia:

W aplikacji Rails:

bundle exec rake zeitwerk:check

W silniku Rails:

bundle exec rake app:zeitwerk:check

2) Użyj Inflectorów, aby poradzić sobie z dziwactwami wielkości liter

Zeitwerk preferuje czcionki camelcase, a jeśli masz klasy składające się z następujących po sobie wielkich liter i nie chcesz zmieniać ich nazw, możesz wykorzystać Zeitwerk::Inflector w inicjatorze Rails:

# config/initializers/zeitwerk.rb
Rails.autoloaders.each do |autoloader|
 autoloader.inflector.inflect(
   'gdpr_handler' => 'GDPRHandler'
 )
end

Bez tego zeitwerk oczekuje, że Twoja klasa będzie nazywać się „GdprHandler”

3) Nie układaj inicjatorów inflektorów w stosy

W naszym silniku Rails utworzyliśmy instancje flektorów, jak pokazano poniżej, ale okazało się, że zostały one nadpisane, gdy aplikacja Rails korzystająca z silnika również utworzyła własne instancje flektorów.

# config/initializers/zeitwerk.rb
Rails.autoloaders.each do |autoloader|
 autoloader.inflector = Zeitwerk::Inflector.new
 autoloader.inflector.inflect(
   'graph_ql_query_service' => 'GraphQLQueryService',
   'graph_ql' => 'GraphQL'
 )
end

Jeśli masz silnik wykorzystujący tę technikę, możesz obejść tę sytuację, konfigurując inicjator w swojej aplikacji Rails, jak pokazano we wskazówce nr 2, aby dodaje do reflektorów, a nie zastępuje ich.

4) Obawy to słowo zastrzeżone

Mieliśmy Rails Concerns w przestrzeni nazw modułu „Concerns” poniżej katalogu „app” w aplikacji Rails. Zeitwerkowi się to nie spodobało. Mieliśmy więc dwie możliwości: usunąć przestrzeń nazw lub zmienić nazwę przestrzeni nazw modułu.

Zmieniliśmy nazwę przestrzeni nazw pliku z informacjami o problemie z „Concerns::Foo” na „Support::Foo”

Przyjrzyjmy się bliżej temu, co to oznacza, aby uzyskać ogólne zrozumienie:

Weźmy na przykład:

# file at /app/foo/concerns/something.rb
module Foo::Concerns
   module Something

Powyższe jest w porządku, tak zrobimy include Foo::Concerns::Something

Ale poniżej nie jest tak:

# file at /app/concerns/something.rb
module Concerns
   module Something

Zeitwerk będzie więc narzekał na to: include ::Concerns::Something

Tak więc zasadniczo nie możesz mieć ::Concerns::Something z tego samego powodu, dla którego nie możesz mieć Models::User or Controllers:UserController

Jeśli nie chcesz zmieniać przestrzeni nazw „Concerns” na coś innego, np. „Support”, możesz wykonać poniższe czynności:

# plik w /app/concerns/something.rb moduł Coś # następnie dołącz jak poniżej dołącz Coś

W ten sposób możesz nadal przechowywać „Zagadnienia” w folderze „Zagadnienia” i uniknąć konieczności zmiany struktury swojej aplikacji.

Zasadniczo nie można mieć modułu zaczynającego się od „Obawy”.

5) Możesz swobodnie wykluczyć łaty małp

W naszym silniku mamy poprawki typu monkey, które naruszały polecenie zeitwerk:check. Na przykład, wprowadzamy pewne niestandardowe zmiany w klasie ActiveResource i musimy wstrzyknąć logikę do klasy Base. Mamy plik o nazwie lib/active_resource/base_ext.rb, który definiuje klasę ActiveResource::Base, ale pojawia się błąd, który mówi, że musi on definiować klasę o nazwie ActiveResource::BaseExt.

Rozwiązanie, które tutaj zastosowaliśmy, polegało po prostu na skonfigurowaniu zeitwerka tak, aby ignorował tę konkretną ścieżkę w folderze lib:

moduł ładujący = Zeitwerk::Loader.for_gem moduł ładujący.ignore(“#{__dir__}/active_resource”)

Uwaga: Później konieczne będzie ręczne zażądanie tych plików.

6) Podziel pojedyncze pliki z wieloma klasami do osobnych plików

W naszym silniku mieliśmy plik wyjątków o nazwach w przestrzeni nazw wyglądających następująco:

# lib/foo/exceptions.rb class MissingConfigurationKeys < StandardError def initialize(msg = 'Brakuje jednego lub więcej wymaganych kluczy konfiguracji lub są one nieprawidłowe') super end end class MappingsOutOfDate < StandardError def initialize(msg = 'Mapowania identyfikatorów są nieaktualne') super end end class ImageNotCopiedError < StandardError def initialize(msg = 'Obraz nie został skopiowany podczas kopiowania produktu') super end end

Zajęcia te były dostępne w aplikacji po prostu pod ich nazwą:

podnieś MissingConfigurationKeys

Reguły Zeitwerk nakazywały nam rozbić te klasy na osobne pliki i odwoływać się do nich za pomocą przestrzeni nazw silnika:

# lib/foo/missing_configuration_keys.rb podnieś Foo::MissingConfigurationKeys

7) Jeśli zdecydujesz się włączyć zeitwerk w silniku Rails, kolejność konfiguracji zeitwerk w głównym interfejsie ma znaczenie!

W pierwszej próbie postąpiliśmy zgodnie z README który przedstawia następującą listę kroków:

# lib/foo.rb (plik główny) wymaga „zeitwerk” loader = Zeitwerk::Loader.for_gem loader.setup # gotowy! moduł Foo # … end loader.eager_load # opcjonalnie

Wszystko wydawało się działać prawidłowo, gdy używaliśmy tej sekwencji i montowaliśmy silnik w naszej aplikacji Rails przy użyciu ścieżki Gemfile lokalnego systemu plików.

Po udostępnieniu silnika jako skompilowanego klejnotu, podczas uruchamiania pojawił się komunikat „Foo nie znaleziono”. Walczyliśmy z tym przez kilka godzin, aż w końcu, po niewielkiej refaktoryzacji, nastąpił moment olśnienia: przenieśliśmy ładowanie zeitwerk. po definicja naszego silnika i to załatwiło sprawę:

# lib/foo.rb (plik główny) wymaga modułu klejnotów wewnętrznych/zewnętrznych Foo end require 'zeitwerk' loader = Zeitwerk::Loader.for_gem loader.ignore(“#{__dir__}/active_resource”) loader.setup loader.eager_load

8) Zwiń katalogi, które istnieją tylko w celach organizacyjnych

Bardzo często zdarza się, że katalogi istnieją tylko w celu nadania aplikacji struktury.

Na przykład załóżmy, że masz klejnot API o nazwie „lokalizacja_api” który zawiera pliki „Kraj” i „Miasto”. Każdy zasób ma osobną klasę, która jest zorganizowana jako lib/location_api/resources/country.rb oraz lib/location_api/resources/city.rb

Teraz Zeitwerk będzie oczekiwać kraj.rb wyglądać mniej więcej tak:

moduł Zasoby Moduł Kraj

A teraz, gdy chcesz użyć tego API, musisz wykonać połączenie, np. LocationApi::Resources::Country

To może być w porządku, jeśli tworzysz nowy gem. Ale jeśli masz już taką strukturę przed przejściem do Zeitwerk, wszystkie istniejące wywołania tego gemu API zostaną… LocationApi::Country.

Może to być proste refaktoryzowanie, w którym odniesienia zostaną zmienione na LocationApi::Resources::CountryAle co, jeśli ten klejnot jest używany przez dużą liczbę aplikacji rozproszonych po całej bazie kodu? Nie jest to takie proste, prawda?

Tutaj właśnie pojawia się funkcja składania Zeitwerka:

ładowarka.collapse(“#{__dir__}/location_api/resources”)

Po prostu dodając dyrektywę „zwiń”, kontynuuj używanie interfejsu API w taki sam sposób LocationApi::Country bez konieczności wprowadzania dalszych zmian w aplikacji.

9) Użyj funkcji szybkiego ładowania, aby wyeliminować ukryte problemy

W pliku głównym silnika możesz poinstruować zeitwerk, aby natychmiast załadował twoje pliki, tak jak pokazano we wskazówce nr 7.

Przeciwieństwem ładowania zachłannego jest ładowanie leniwe, które ignoruje klasy, dopóki ścieżka kodu, w której się znajdują, nie zostanie aktywowana przez jakiś sygnał wejściowy (wywołanie API, kliknięcie widoku itp.). Odkryliśmy, że włączenie ładowania zachłannego pomogło nam zwiększyć pewność, że niczego nie pominęliśmy.

To wszystko! 8 porad i trików, które wykorzystaliśmy, aby przejść z klasycznego autoloadera na Zeitwerk w jednym z naszych produktów. Produkt działa teraz sprawnie, wykorzystując Sidekiq 6 i Rails 6 w środowisku produkcyjnym. Odblokował również możliwość aktualizacji naszej wersji Redis!

Jeśli utknąłeś lub nie masz pewności co do aktualizacji autoloadera, mamy nadzieję, że tych 8 wskazówek pomoże Ci uporać się z tym problemem w Twojej aplikacji Rails i być może oszczędzi Ci trochę czasu.

Oto kilka źródeł, które uznaliśmy za przydatne:

Szczególne podziękowania dla naszych przyjaciół z Rewind za ich spostrzeżenia na ten temat.
Strategie rozwoju Shopify dla marek DTC | Steve Hutt | Były menedżer ds. sukcesu sprzedawców Shopify | Ponad 440 odcinków podcastu | 50 tys. pobrań miesięcznie