flytta från CarrierWave till ActiveStorage i en Rails-app

NJ Pearman
NJ Pearman

följ

Jun 20, 2018 * 9 min läs

vi använder Ruby on Rails för att undervisa webbapplikationsutveckling på EPFL Extension School. Det är en bra ram som är solid, beprövad och pålitlig och presenterar en lätt att följa struktur när du tar dina första steg att lära dig om webbutveckling.

men det är också en ständigt utvecklande mjukvara, med förbättringar och nya funktioner som släpps varje år. En av de senaste tilläggen till Rails i version 5.2 är ActiveStorage-funktionen, som lägger till enkel filuppladdningshantering till core Rails-ramverket för första gången.

i den första iterationen av vårt webbapplikationsutvecklingsprogram inkluderar vi ett ämne för att lära oss hur man lägger till filuppladdningar i en Rails-applikation. Vi använder dock Rails 5.1 i programmet, och filuppladdningsämnet använder en av de allmänt använda tredjepartslösningarna för att lägga till filuppladdningar, kallad CarrierWave. Detta är en solid tredje part pärla som tillåter oss att genomföra filuppladdningar i en Rails app och används i många verkliga Ruby on Rails apps-inklusive vår elev plattform!

men med introduktionen av ActiveStorage blir dessa tredje parts pärlor mindre attraktiva än den här nya lösningen buntad inuti skenor. Faktum är att Paperclip, en av de andra populära tredjepartsfiluppladdningspärlorna, redan har meddelat att den är föråldrad till förmån för ActiveStorage. Utvecklarna av Paperclip har insett att ActiveStorage är ett bättre val för utvecklare och slutat ytterligare arbete på sin egen pärla.

så låt oss titta specifikt på vad som krävs för att flytta från CarrierWave i Rails 5.1 till ActiveStorage i Rails 5.2.

applikationen

i webbapplikationsutvecklingsprogrammet arbetar vi genom att bygga en webbapplikation som heter My Bucket List. Detta är en app som tillåter användare att skapa och spåra upplevelser som de alltid har velat åstadkomma. Användare kan se vad andra människor har skapat och spåra dem också. En av funktionerna i appen tillåter en användare att ladda upp sin egen avatar, och vi bygger den funktionen för att lära sig om filuppladdningar och bilagor med CarrierWave.

en användare kan ladda upp en avatar med det här formuläret med CarrierWave

så först, låt oss få en snabb genomgång av vad som är inblandat med att lägga till en enkel bilaga med CarrierWave.

carrierwave-konfiguration

för att inkludera CarrierWave i ett projekt måste vi:

  • Lägg till CarrierWave gem till Gemfile.
  • inkludera CarrierWave adapter för ActiveRecord i en config initializer, config/initializers/carrierwave.rb.

och sedan för att lägga till en bildbilaga till en modell måste vi:

  • generera en uppladdare med rails generate uploader UploaderName.
  • Lägg till ett attribut på modellen för att lagra det bifogade filnamnet för varje post, med tillhörande databasmigrering.
  • redigera värden i uppladdaren, till exempel ladda upp lagringsplats och standardbild.
  • använd makrot mount_uploader i modellen för att inkludera den specifika uppladdaren.
  • Lägg till ett filformulärfält där en bild kan laddas upp.
  • Lägg till attributet modell i listan med starka parametrar i styrenheten som hanterar formuläret som innehåller filfältet.

låt oss överväga en av dessa punkter ytterligare: i CarrierWave är det nödvändigt att lägga till specifika attribut till alla modeller som behöver ha en bifogad fil. Till exempel behöver en User – modell som behöver en avatar – bild som är kopplad till den ett attribut som heter :avatar som är en String. Detta kräver en databasmigrering för att lägga till den underliggande databaskolumnen, plus att skapa och montera en Uploader – klass till det attributet i modellen.

Detta är inte särskilt mödosamt men som vi ser kräver ActiveStorage mycket mindre kod från fall till fall.

ytterligare en punkt att lyfta fram är att i min app — My Bucket List app — CarrierWave avatar uploader är inställd med standard enkel fillagring. I ordningsord lagras uppladdade bilder någonstans i mappen public/ i applikationen. Den exakta sökvägen definieras inom klassen Uploaderför avataren och är inställd på "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}". Detta är en sökväg i förhållande till mappen public/, så att uppladdade bilder är direkt tillgängliga via webbservern. Detta möjliggör direkt åtkomst till bifogade filer, som vi kan kontrastera med ActiveStorage senare.

uppgradera Rails

innan du tittar på ActiveStorage är det nödvändigt att uppgradera till Rails 5.2. Detta är en uppgift som kan vara ganska involverad, beroende på komplexiteten i din ansökan. Applikationen som jag använder här, som vi bygger i vårt WAD-program, är inte särskilt svår att uppdatera men det behöver fortfarande lite omsorg och uppmärksamhet.

här är vad jag gjorde för att uppdatera My Bucket List-applikationen från Rails 5.1 till Rails 5.2.

först skapade jag en ny filial i mitt git — arkiv för att isolera uppgraderingen-det är viktigt att kunna gå tillbaka till den tidigare arbetsversionen av en app om något går fel i uppgraderingsprocessen!

på den nya grenen ändrade jag versionen av Rails i Gemfile från '~> 5.1.2' till '~> 5.2.0' och sprang sedan bin/bundle update rails — det här kommandot hämtar den nya versionen av rails och alla relaterade pärlor i applikationen. För min ansökan, det fanns inga pärla konflikter men om du använder tredje part pärlor, kan du behöva lösa konflikter mellan olika pärla versioner på denna punkt!

när du har installerat den nya Rails gem och det är beroenden, är det nödvändigt att uppdatera själva programmet. Jag gjorde detta med bin/bundle exec rails app:update. Detta kommando uppdaterar programmatiskt alla nödvändiga filer i applikationen för att fungera med Rails 5.2.

men… det här kommandot kommer att skriva över ändringar som du har gjort i din ansökan, till exempel config/routes.rb. Lyckligtvis frågar kommandot om man ska skriva över varje fil, och det är möjligt att diff någon av dessa filer under denna process för att kontrollera vad som skulle skrivas över. Prompten för varje överskrivning är , vilket betyder:

  • Y för ”ja, Skriv över min fil”, och är standardalternativet om du bara trycker på Enter.
  • n för ”nej, skriv inte över min fil”
  • a för ” ja, Skriv över den här filen och skriv över alla andra filer också!”. (Min allmänna regel är aldrig Använd a).
  • q för ”avsluta denna process”
  • d för ”Visa mig skillnaderna mellan min fil och överskrivningen”
  • h för ”Visa mig en lista över vad Ynaqdh betyder”

i min ansökan accepterade jag varje överskrivning med Y utom config/routes.rb och config/locales/en.yml. Dessa två filer var filer som jag hade ändrat och så jag ville behålla min version, så valde n.

denna uppgraderingsprocess kan vara mer involverad om du har en mer komplex applikation, särskilt om du har massor av anpassad konfiguration i någon av miljökonfigurationsfilerna, dvs. config/environments/production.rb, config/environments/test.rb och config/environments/development.rb. Uppgraderingen lägger till viktiga inställningar för dessa filer, men du vill också behålla din egen anpassade konfiguration — det är här att ha den ursprungliga versionen av applikationen i en separat git-gren hjälper. Det är då möjligt att koden i den här gamla grenen för att kontrollera att all din programkod och konfiguration fortfarande är på plats efter uppgraderingen.

efter att ha kört bin/bundle exec rails app:update var det nödvändigt för mig att lägga till bootsnap pärla till Gemfile. Detta är en ny pärla som används i Rails 5.2 men den läggs inte till som en del av kommandot app:upgrade. Så jag lade bara till gem 'bootsnap' till Gemfileoch sprang sedan bin/bundle install.

efter detta startade min Bucket List-applikation som tidigare med rails server.

ersätta CarrierWave med ActiveStorage

så, med applikationen som nu körs på Rails 5.2, kunde jag börja ersätta CarrierWave med ActiveStorage.

med ActiveStorage är det onödigt att lägga till modellspecifika attribut för att lagra de bifogade filnamn som är nödvändiga med CarrierWave. ActiveStorage fungerar med samma två associerade tabeller för alla bilagor.

för att ställa in dessa två tabeller sprang jag bin/bundle exec rails active_storage:install följt av rails db:migrate. De två tabellerna är active_storage_blobs och active_storage_attachments; den första är för detaljerna i den bifogade filen och den andra är för den polymorfa kopplingstabellen som länkar en bifogad fil till en modellpost.

och här är den viktiga punkten: när vi har skapat dessa två tabeller behöver vi inte skapa några andra migreringar för att inkludera bilagor i våra modeller! Detta gör ActiveStorage lätt att arbeta med ur ett databasperspektiv.

därefter tittade jag på att ersätta implementeringen av :avatar – bilagan med ActiveStorage istället för CarrierWave. I min app har varje Useren :avatar. Eftersom jag använde CarrierWave tidigare hade jag ett :avatar attribut monterat på en CarrierWave Uploader i User – modellen, deklarerad så här:

class User < ApplicationRecord
# ... various codez mount_uploader :avatar, AvatarUploader # ... other codez
end

carrierwave :avatar – bilagan kan ersättas med en ActiveSupport-bilaga genom att använda has_one_attached :avatar, så här:

class User < ApplicationRecord
# ... various codez # commented old uploader for reference
# mount_uploader :avatar, AvatarUploader
has_one_attached :avatar # ... other codez
end

det är en ändring till en rad kod. Vid denna tidpunkt, vad mer behöver göras? Till exempel, hur är uppladdningslagringsplatsen inställd? Kom ihåg att i min app är CarrierWave avatar uploader inställd med standard enkel fillagring, och platsen för detta är uttryckligen inställd i filen avatar_uploader.rb. Enkel fillagring är standard i ActiveStorage också. Platsen är inställd i filen config/storage.yml, med ett standardvärde för lokala uppladdningar.

standardkonfigurationen för ActiveStorage betyder att jag inte behöver skriva mer kod för mina uppladdningar för att fungera för det modifierade :avatar attributet i min ansökan. Jag har ändrat uppladdningsmekanismen helt från CarrierWave till ActiveStorage och jag behöver inte göra någonting mer: Jag behöver inte göra några ändringar i styrenheten som hanterar uppladdningen, eftersom :avatar redan är deklarerad som en stark parameter. Och jag behöver inte ändra fältet för filformulär i vyn som tillåter användare att välja en bild att ladda upp, eftersom det stöds av :avatar ”attribut”.

men det finns ytterligare en förändring som jag behöver göra för att migrera från CarrierWave till ActiveStorage, och det är hur man använder den bifogade bilden i vyer. Med CarierWave använde jag avatar_url – metoden för att göra hela bildvägen. Med ActiveStorage återges inte FILADRESSEN från själva attributet för bifogad fil, utan återges genom att attributet skickas till hjälpmetoder. Så den fullständiga bifogad URL kan göras med url_for(user.avatar), eller direkt med image_tag.

det är också nödvändigt att uttryckligen kontrollera om bilagan är närvarande, så en fullständig användning i en vy skulle se ut så här:

<% if current_user.avatar.attached? %>
<%= image_tag current_user.avatar, class: 'avatar' %>
<% else %>
<%= image_tag 'default-avatar', class: 'avatar' %>
<% end %>

när jag uppdaterade referenserna till user.avatar_url i mina åsikter med utdrag som ovan, hade jag flyttat helt från CarrierWave till ActiveStorage för alla nya uppladdningar.

den gamla CarrierWave-koden måste städas upp, och det finns en fråga om vad man ska göra med befintliga uppladdningar som gjordes med CarrierWave. Men se nedan om det…

mer komplexa scenarier

nästan alla produktionsscenarier kommer att vara mer komplexa än den jag skisserade ovan. Det kommer att bli nödvändigt att överväga saker som uppladdningar lagras på CDn eller fjärrservrar som AWS S3, och bildstorleksändring för miniatyrer, etc. ActiveStorage tillåter oss att göra en hel del av dessa saker ur lådan också och verkar mycket väl konstruerad för utvecklarens behov. Som du kan förvänta dig finns det bra dokumentation i Rails guide.

när det gäller att migrera befintliga uppladdningar från CarrierWave till ActiveStorage, skulle detta säkert vara möjligt med ett relativt litet rake-skript. Jag kommer att sträva efter att täcka det i en framtida post.

detta var ett enkelt scenario, men totalt sett var jag verkligen nöjd med hur lätt det var att använda ActiveStorage och ersätta CarrierWave med det. Jag gillar också tanken som har gått in i de olika delarna av ActiveStorage, eftersom allt verkar vara i filer och mappar som snyggt matchar strukturen på resten av skenorna. Jag tycker definitivt att det är värt att komma in i Rails 5.2 för att kunna använda ActiveStorage för filuppladdningar i dina applikationer!

Läs mer!

intresserad av att lära dig mer om Ruby och Ruby on Rails? Jag undervisar webbapplikationsutveckling på EPFL Extension School, en certifierad Online inlärningsplattform som undervisar digitala färdigheter inom datavetenskap, webbapplikationsutveckling och mer. EPFL är ett av världens ledande universitet och rankas som” nummer 1 ungt universitet ” av Times Higher Education Ranking.



+