• Udforsk. Lær. Triv. Fastlane Media Network

  • e-handel Fastlane
  • PODFastlane
  • SEOfastlane
  • RådgiverFastlane
  • TheFastlaneInsider

9 tips og tricks til at aktivere Zeitwerk Autoloader i din Rails-app

9 tips og tricks til at aktivere Zeitwerk Autoloader i din Rails-app

medforfattet af Sanket Patel



Introduktion

Har du en Rails 5 (eller ældre) app, der bruger Sidekiq, og ønsker du at opgradere til den nyeste og bedste version af begge? Hvis du har, så følg med for at se nogle nyttige tips og tricks, som vi opdagede under denne situation, og som forhåbentlig vil hjælpe dig med at spare tid under din egen opgradering.

Hos Rewind bruger vi Sidekiq 5 i vid udstrækning til vores sikkerhedskopiering og kopiering af apps asynkrone job.

Vi bruger en Rails Engine monteret i en Rails-app, der betjener Sidekiq. Enginen indeholder alle workers og anden forretningslogik. Det ser nogenlunde sådan ud:

arbejdere og anden forretningslogik

Under vores opgradering fra Rails 5 til 6 opdagede vi, at vores gems og Rails-motor havde kode, der var inkompatibel med den nye standard autoloader kaldet Zeitwerk, og applikationsserverne ville ikke starte. Vi lærte også, at Sidekiq 6 kræver zeitwerk autoloader og vil ikke fungere med klassisk tilstand.

Opgradering af hovedversionen af ​​et kernebibliotek fra en tredjepart skaber en del bekymring. Tilføjer du en fundamental ændring i, hvordan appen indlæser og læser klasser? Av.

Holdet besluttede at implementere en løsning ved at vende tilbage til den klassiske version af autoloaderen og lade Sidekiq være på v5.

Ikke desto mindre var det næsten et år efter udgivelsen af ​​Sidekiq 6, og en opgradering var længe påtrængende.

Sidekiq 6.1 var nu udgivet, og den inkluderede en række sikkerheds-/fejlrettelser og forbedringer, der ville forbedre vores service – vi behov for at finde ud af, hvordan dette ville udspille sig på vores platform.

I klassisk Rewind-stil afsatte vi noget tid og udarbejdede en plan for at begrænse opgraderingens eksplosionsradius.

Her er 9 tips og tricks, du bør kende, før du går i gang med din egen opgradering:

1) zeitwerk:check er din ven

Zeitwerk-perlen er en del af Rails 6, og den indeholder et praktisk kontrolværktøj, der scanner din projektmappe og forsøger at indlæse hurtigt, ligesom din applikation ville gøre ved opstart. Vi fandt 2 måder at bruge den på:

I en Rails-app:

pakke exec rake zeitwerk:check

I en Rails-motor:

pakke exec rake app:zeitwerk:check

2) Brug bøjningsfunktioner til at håndtere særheder med store og små bogstaver

Zeitwerk kan lide camelcase, og hvis du har klasser med fortløbende store bogstaver og ikke ønsker at omdøbe dem, kan du bruge Zeitwerk::Inflector i en Rails-initialisering:

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

Uden dette forventer zeitwerk, at din klasse hedder "GdprHandler"

3) Stable ikke inflektorinitialiseringer

I vores Rails Engine instantierede vi inflektorer som vist nedenfor, men opdagede, at de blev tilsidesat, da Rails-appen, der brugte engine'en, også instantierede sine egne inflektorer.

# 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

Hvis du har en motor, der bruger denne teknik, kan du omgå denne situation ved at konfigurere initialiseringen i din Rails-app som vist i tip #2, så den tilføjer til inflktorerne og erstatter dem ikke.

4) Bekymringer er et reserveret ord

Vi havde Rails Concerns i et "Concerns"-modulnavneområde under "app"-mappen i Rails-appen. Zeitwerk kunne ikke lide dette. Så vi havde 2 valgmuligheder: Fjern navneområdet eller omdøb modulnavneområdet.

Vi valgte at omdøbe navneområdet for bekymringsfilen fra "Concerns::Foo" til "Support::Foo".

Lad os se lidt nærmere på, hvad dette betyder for at få en generel forståelse:

Så tag et eksempel:

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

Ovenstående er fint, da vi vil gøre det include Foo::Concerns::Something

Men det nedenstående er ikke:

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

Så zeitwerk vil klage over dette: include ::Concerns::Something

Så grundlæggende kan du ikke have ::Concerns::Something af samme grund kan du ikke have Models::User or Controllers:UserController

Hvis du ikke ønsker at ændre navneområdet "Bekymringer" til noget andet som "Support", kan du gøre følgende:

# fil på /app/concerns/something.rb modul Noget # inkluder derefter som vist nedenfor include Something

På denne måde kan du stadig have dine "Bekymringer" i mappen "bekymringer" og undgå at ændre strukturen i din ansøgning.

Generelt kan du ikke have et modul, der starter med "Bekymringer".

5) Du er velkommen til at udelukke abe-pletter

Vi har monkey patches i vores engine, og disse overtrådte zeitwerk:check-kommandoen. For eksempel laver vi nogle brugerdefinerede ting til ActiveResource og skal injicere noget logik i Base-klassen. Vi har en fil med navnet lib/active_resource/base_ext.rb, som definerer klassen ActiveResource::Base, men den fejl, vi modtager, siger, at denne skal definere en klasse med navnet ActiveResource::BaseExt.

Løsningen vi valgte her var simpelthen at konfigurere zeitwerk til at ignorere denne specifikke sti i lib-mappen:

loader = Zeitwerk::Loader.for_gem loader.ignore(“#{__dir__}/active_resource”)

Bemærk: Du skal manuelt anmode om disse filer senere.

6) Opdel enkelte filer med flere klasser i deres egne filer

Vi havde en exceptions-fil med navneafstand i vores motor som denne:

# lib/foo/exceptions.rb class MissingConfigurationKeys < StandardError def initialize(msg = 'En eller flere nødvendige konfigurationsnøgler mangler eller er ugyldige') super end end class MappingsOutOfDate < StandardError def initialize(msg = 'ID-mappings er forældede') super end end class ImageNotCopiedError < StandardError def initialize(msg = 'Billede blev ikke kopieret under produktkopiering') super end end

Disse klasser var tilgængelige i hele appen blot ved deres navn:

hæv ManglendeKonfigurationsnøgler

Zeitwerk-reglerne fik os til at opdele disse klasser i deres egne filer og referere til dem ved hjælp af engine-navnerummet:

# lib/foo/missing_configuration_keys.rb raise Foo::MissingConfigurationKeys

7) Hvis du beslutter dig for at aktivere zeitwerk i en Rails Engine, er den rækkefølge, du konfigurerer zeitwerk i din hovedgrænseflade, vigtig!

I første forsøg fulgte vi README som angiver trinnene som følger:

# lib/foo.rb (hovedfil) kræver “zeitwerk” loader = Zeitwerk::Loader.for_gem loader.setup # klar! modul Foo # … slut loader.eager_load # valgfrit

Alt syntes at fungere fint, når vi brugte denne sekvens og monterede motoren i vores Rails-app ved hjælp af en lokal Gemfile-sti i filsystemet.

Efter at have udgivet Engine som en indbygget perle, eksploderede tingene under opstart med beskeden "Foo not found". Vi kæmpede med dette i et par timer, og til sidst kom eureka!-øjeblikket efter lidt refactoring: Vi flyttede zeitwerk-indlæsningen. efter definitionen af ​​vores motor, og det gjorde tricket:

# lib/foo.rb (hovedfil) kræver internt/eksternt gems-modul Foo end kræver 'zeitwerk' loader = Zeitwerk::Loader.for_gem loader.ignore(“#{__dir__}/active_resource”) loader.setup loader.eager_load

8) Skjul mapper, der kun findes til organisering

Det er meget almindeligt at have mapper, der kun eksisterer med det formål at give struktur til din applikation.

For eksempel, antag at du har en API-perle ved navn "placering_api" som har filerne Land og By. Hver ressource har en separat klasse, der er organiseret som lib/location_api/ressourcer/land.rb og lib/location_api/ressourcer/by.rb

Nu forventer Zeitwerk land.rb at være noget i retning af nedenstående:

modul Ressourcer Modul Land

Og når du nu vil bruge denne API, skal du foretage et kald i retning af noget i retning af LocationApi::Resources::Country

Dette kan være fint, hvis du bygger en ny perle. Men hvis du har en eksisterende struktur som denne, før du flytter til zeitwerk, vil alle eksisterende kald til denne API-perle blive LocationApi::Country.

Dette kunne være en simpel refaktorering, hvor referencer ændres til LocationApi::Resources::CountryMen hvad nu hvis denne perle bruges af et stort antal applikationer spredt ud over hele din kodebase? Ikke så simpelt, vel?

Her kommer Zeitwerks kollapsfunktionalitet ind i billedet:

loader.collapse(“#{__dir__}/location_api/ressourcer”)

Ved blot at tilføje collapse-direktivet, fortsæt med at bruge API'en som LocationApi::Country uden yderligere ændringer i din ansøgning.

9) Brug ivrig indlæsning til at luge skjulte problemer ud

I din motors hovedfil kan du instruere zeitwerk til at indlæse dine filer hurtigt, som vist i tip #7.

Det modsatte af "eager loading" er "lazy loading", som ignorerer dine klasser, indtil den kodesti, de er på, aktiveres af et input (API-kald, visningsklik osv.). Vi fandt ud af, at aktivering af "eager loading" hjalp os med at øge vores tillid til, at vi ikke overså noget.

Det var det! 8 tips og tricks, som vi brugte til at skifte fra den klassiske til Zeitwerk autoloader i et af vores produkter. Produktet kører nu med Sidekiq 6 og Rails 6 i produktion. Det har også åbnet op for muligheden for at opgradere vores Redis-version!

Hvis du har stået fast eller er usikker på at opgradere din autoloader, håber vi, at disse 8 tips vil hjælpe dig med at løse problemet i din egen Rails-app og måske spare dig lidt tid i processen.

Her er nogle referencer, som vi fandt nyttige:

En særlig tak til vores venner på Rewind for deres indsigt i dette emne.
Shopify vækststrategier for DTC-brands | Steve Hutt | Tidligere Shopify Merchant Success Manager | 440+ podcast-episoder | 50 månedlige downloads