Verplaatsen van CarrierWave te ActiveStorage in een Rails app

NJ Pearman
NJ Pearman

Volg

Jun 20, 2018 · 9 min lezen

Wij maken gebruik van Ruby on Rails leren de web applicatie ontwikkeling in de EPFL Uitbreiding van de School. Het is een geweldig kader dat is solide, beproefd en vertrouwd en presenteert een eenvoudig te volgen structuur bij het nemen van uw eerste stappen leren over webontwikkeling.

maar het is ook een voortdurend evoluerend stuk software, met verbeteringen en nieuwe functies die elk jaar worden uitgebracht. Een van de recente toevoegingen aan Rails in versie 5.2 is de ActiveStorage-functie, die voor het eerst eenvoudig bestand uploadbeheer toevoegt aan het Core Rails-framework.

in de eerste iteratie van ons ontwikkelprogramma voor webtoepassingen, nemen we een onderwerp op om te leren hoe u bestanden kunt uploaden in een Rails-toepassing. We gebruiken Rails 5.1 in het programma echter, en het onderwerp bestand uploaden maakt gebruik van een van de veelgebruikte oplossingen van derden voor het toevoegen van bestand uploads, genaamd CarrierWave. Dit is een solide derde partij juweeltje dat ons in staat stelt om te implementeren bestand uploads in een Rails app en is in gebruik in veel Real-world Ruby on Rails apps-met inbegrip van onze leerling platform!

maar met de introductie van ActiveStorage worden deze edelstenen van derden minder aantrekkelijk dan deze nieuwe oplossing gebundeld in Rails. In feite, Paperclip, een van de andere populaire derden bestand uploaden edelstenen, heeft al aangekondigd dat het wordt afgekeurd ten gunste van ActiveStorage. De ontwikkelaars van Paperclip hebben erkend dat ActiveStorage is een betere keuze voor ontwikkelaars en gestopt verder werken aan hun eigen gem.

dus laten we eens specifiek kijken naar wat er nodig is om van CarrierWave in Rails 5.1 naar Activestore in Rails 5.2.

de toepassing

in het ontwikkelingsprogramma voor webapplicaties werken we aan het bouwen van een webapplicatie genaamd My Bucket List. Dit is een app die gebruikers in staat stelt om te creëren en bijhouden van ervaringen die ze altijd al hebben willen bereiken. Gebruikers kunnen zien wat andere mensen hebben gemaakt en bijhouden die ook. Een van de functies in de app kan een gebruiker om hun eigen avatar te uploaden, en we bouwen die functie om te leren over het uploaden van bestanden en bijlagen met behulp van CarrierWave.

een gebruiker kan een avatar uploaden met dit formulier, gebruikmakend van CarrierWave

dus laten we eerst een kort overzicht hebben van wat er te maken heeft met het toevoegen van een eenvoudige bijlage met CarrierWave.

CarrierWave configuratie

om CarrierWave in een project op te nemen, moeten we:

  • voeg de CarrierWave gem toe aan de Gemfile.
  • voeg de CarrierWave-adapter voor ActiveRecord toe aan een config-initializer, config/initializers/carrierwave.rb.

en om een afbeeldingsbijlage aan een model toe te voegen, moeten we:

  • Genereer een Uploader met rails generate uploader UploaderName.
  • voeg een attribuut toe aan het model om de bijgevoegde bestandsnaam voor elke record op te slaan, met bijbehorende databasemigratie.
  • Bewerk waarden in de uploader, zoals opslaglocatie uploaden en standaard afbeelding.
  • gebruik de mount_uploader macro in het model om de specifieke uploader op te nemen.
  • voeg een bestandsvorm toe waar een afbeelding kan worden geüpload.
  • voeg het model-attribuut toe aan de lijst met sterke parameters in de controller die het formulier met het bestandsveld afhandelt.

laten we een van deze punten verder bekijken: in CarrierWave is het noodzakelijk om specifieke attributen toe te voegen aan elk model dat een bijgevoegd bestand nodig heeft. Een User – model dat een avatar – afbeelding nodig heeft, heeft bijvoorbeeld een attribuut :avatar nodig dat een Stringis. Dit vereist een databasemigratie om de onderliggende databasekolom toe te voegen, plus het maken en aankoppelen van een Uploader – klasse aan dat attribuut in het model.

Dit is niet bijzonder omslachtig, maar zoals we zullen zien, vereist ActiveStorage veel minder code per geval.

nog een punt om te benadrukken is dat in mijn app — de Mijn Bucket List app — de CarrierWave avatar uploader is ingesteld met de standaard eenvoudige bestandsopslag. In volgorde woorden, geüploade afbeeldingen worden ergens opgeslagen in de public/ map in de toepassing. Dat precieze pad is gedefinieerd binnen de klasse Uploader voor de avatar, en is ingesteld op "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}". Dit is een pad relatief aan de public/ map, zodat geüploade afbeeldingen direct toegankelijk zijn via de webserver. Dit maakt directe toegang tot de bijlage bestanden, die we kunnen contrast met ActiveStorage later.

Rails upgraden

voordat we naar ActiveStorage kijken, is het noodzakelijk om te upgraden naar Rails 5.2. Dit is een taak die behoorlijk kan worden betrokken, afhankelijk van de complexiteit van uw toepassing. De applicatie die ik hier gebruik, die we in ons WAD-programma bouwen, is niet bijzonder moeilijk te updaten, maar het heeft nog steeds wat zorg en aandacht nodig.

hier is wat ik deed om de Mijn Bucket List applicatie bij te werken van Rails 5.1 naar Rails 5.2.

eerst heb ik een nieuwe branch aangemaakt in mijn Git repository om de upgrade te isoleren — het is belangrijk om terug te kunnen gaan naar de vorige werkende versie van een app als er iets mis gaat in het upgrade proces!

op de nieuwe branch heb ik de versie van Rails in de Gemfile veranderd van '~> 5.1.2' naar '~> 5.2.0', en vervolgens bin/bundle update rails uitgevoerd — dit commando downloadt de nieuwe versie van rails en alle gerelateerde edelstenen in de applicatie. Voor mijn toepassing, waren er geen gem conflicten, maar als u gebruik maakt van derden edelstenen, moet u mogelijk conflicten tussen verschillende gem versies op dit punt op te lossen!

na het installeren van de nieuwe Rails gem en zijn afhankelijkheden, is het noodzakelijk om de toepassing zelf bij te werken. Ik deed dit met bin/bundle exec rails app:update. Dit commando werkt programmatisch alle benodigde bestanden in de applicatie bij om met Rails 5.2 te werken.

maar … dit commando zal de wijzigingen die u in uw toepassing hebt aangebracht, zoals config/routes.rb, overschrijven. Gelukkig vraagt het commando of elk bestand moet worden overschreven, en het is mogelijk om diff elk van deze bestanden tijdens dit proces te controleren wat er zou worden overschreven. De prompt voor elke overschrijf is , wat betekent:

  • Y voor “Ja, overschrijf mijn bestand”, en is de standaard optie als je gewoon op Enterdrukt.
  • n Voor “Nee, overschrijf mijn bestand niet”
  • a voor ” Ja, overschrijf dit bestand en overschrijf elk ander bestand ook!”. (Mijn algemene regel is nooit agebruiken).
  • q voor “dit proces afsluiten”
  • d voor “Toon me de verschillen tussen mijn bestand en de overschrijven”
  • h voor “Toon me een lijst van wat Ynaqdh betekent”

In mijn aanvraag accepteerde ik elke overschrijf met Y behalve config/routes.rb en config/locales/en.yml. Deze twee bestanden waren bestanden die ik had veranderd en dus wilde ik mijn versie behouden, dus koos n.

dit upgradeproces kan meer betrokken zijn als u een complexere toepassing hebt, vooral als u veel aangepaste configuratie hebt in een van de omgevingsconfiguratiebestanden, d.w.z. config/environments/production.rb, config/environments/test.rb en config/environments/development.rb. De upgrade voegt belangrijke instellingen toe aan deze bestanden, maar je zult ook je eigen aangepaste configuratie willen behouden — dit is waar het hebben van de originele versie van de applicatie in een aparte Git branch helpt. Het is dan mogelijk om de code in deze oude branch te controleren of al je applicatie code en configuratie nog steeds op zijn plaats is na de upgrade.

na het draaien van bin/bundle exec rails app:update was het voor mij noodzakelijk om de bootsnap gem toe te voegen aan de Gemfile. Dit is een nieuw gem dat gebruikt wordt in Rails 5.2, maar het is niet toegevoegd als onderdeel van het app:upgrade Commando. Dus ik heb gewoon gem 'bootsnap' toegevoegd aan de Gemfile en toen liep bin/bundle install.

hierna is mijn Bucket List-toepassing gestart zoals voorheen met rails server.

CarrierWave vervangen door ActiveStorage

dus, met de toepassing die nu op Rails 5.2 draait, kan ik beginnen CarrierWave te vervangen door ActiveStorage.

met ActiveStorage is het niet nodig om modelspecifieke attributen toe te voegen om de bestandsnamen van de bijlage op te slaan die nodig zijn met CarrierWave. ActiveStorage werkt met dezelfde twee bijbehorende tabellen voor alle bijlagen.

om deze twee tabellen op te stellen, liep ik bin/bundle exec rails active_storage:install gevolgd door rails db:migrate. De twee tabellen zijn active_storage_blobs en active_storage_attachments; de eerste is voor de details van het bijgevoegde bestand en de tweede is voor de polymorfe join table die een bijgevoegd bestand koppelt aan een modelrecord.

en hier is het belangrijke punt: zodra we deze twee tabellen hebben gemaakt, hoeven we geen andere migraties te maken om bijlagen in onze modellen op te nemen! Dit maakt ActiveStorage gemakkelijk om mee te werken vanuit een database perspectief.

vervolgens heb ik gekeken naar het vervangen van de implementatie van de :avatar bijlage door ActiveStorage in plaats van CarrierWave. In mijn app heeft elke User een :avatar. Omdat ik CarrierWave eerder gebruikte, had ik een :avatar attribuut aangekoppeld aan een CarrierWave Uploader in het User model, zo verklaard:

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

de CarrierWave :avatar bijlage kan worden vervangen door een ActiveSupport bijlage met has_one_attached :avatar, zoals hier:

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

dat is een verandering in één regel code. Wat moet er nu nog meer gebeuren? Bijvoorbeeld, hoe is de upload opslaglocatie ingesteld? Onthoud dat in mijn app de CarrierWave avatar Uploader is ingesteld met de standaard eenvoudige bestandsopslag, en de locatie hiervoor is expliciet ingesteld in het avatar_uploader.rb bestand. Eenvoudige bestandsopslag is ook de standaard in ActiveStorage. De locatie is ingesteld in het config/storage.yml bestand, met een standaardwaarde voor lokale uploads.

de standaardconfiguratie voor ActiveStorage betekent dat ik geen code meer hoef te schrijven voor mijn uploads om te werken voor het gewijzigde :avatar attribuut in mijn toepassing. Ik heb het uploadmechanisme volledig veranderd van CarrierWave naar ActiveStorage en ik hoef niets meer te doen: Ik hoef geen wijzigingen aan te brengen in de Controller die de upload beheert, omdat :avatar al is gedeclareerd als een sterke parameter. En ik hoef het bestandsvorm veld niet te wijzigen in de weergave waarmee gebruikers een afbeelding kunnen selecteren om te uploaden, omdat dit wordt ondersteund door het :avatar “attribuut”.

maar er is nog een verandering die ik moet maken om te migreren van CarrierWave naar ActiveStorage, en dat is hoe de bijgevoegde afbeelding in weergaven te gebruiken. Met CarierWave gebruikte ik de avatar_url methode om het volledige afbeeldingspad weer te geven. Met ActiveStorage wordt de URL van het bestand niet weergegeven uit het attribuut attachment zelf, maar weergegeven door het attribuut door te geven aan helper-methoden. Dus de volledige bijlage URL kan worden gerenderd met url_for(user.avatar), of direct met image_tag.

het is ook nodig om expliciet te controleren of de bijlage aanwezig is, zodat een volledig gebruik in een weergave er ongeveer zo uit zou zien:

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

zodra ik de verwijzingen naar de user.avatar_url in mijn weergaven met fragmenten zoals hierboven bijgewerkt, was ik volledig verhuisd van CarrierWave naar ActiveStorage voor alle nieuwe uploads.

de oude CarrierWave code moet worden opgeruimd, en er is een vraag over wat te doen met bestaande uploads die werden gedaan met CarrierWave. Maar zie hieronder over dat…

complexere scenario ‘s

bijna alle productiescenario’ s zullen complexer zijn dan de hierboven geschetste. Het zal nodig zijn om dingen te overwegen zoals uploads worden opgeslagen op CDN ‘ s of externe servers zoals AWS S3, en image resizing voor miniaturen, enz. ActiveStorage stelt ons in staat om veel van die dingen uit de doos te doen en lijkt zeer goed ontworpen voor de behoeften van ontwikkelaars. Zoals je zou verwachten, is er goede documentatie in de Rails gids.

met betrekking tot het migreren van bestaande uploads van CarrierWave naar ActiveStorage, zou dit zeker mogelijk zijn met een relatief klein Rake script. Ik zal ernaar streven dat in een toekomstige functie te behandelen.

dit was een eenvoudig scenario, maar over het algemeen was ik erg blij met hoe gemakkelijk het was om gebruik te maken van ActiveStorage en CarrierWave ermee te vervangen. Ik hou ook van de gedachte die is gegaan in de verschillende delen van ActiveStorage, zoals alles lijkt te zijn in bestanden en mappen die mooi overeenkomen met de structuur van de rest van de Rails. Ik denk zeker dat het de moeite waard om in Rails 5.2 om ActiveStorage gebruiken voor het uploaden van bestanden in je applicaties!

meer informatie!

geïnteresseerd in meer informatie over Ruby, en Ruby on Rails? Ik geef les in ontwikkeling van webapplicaties aan de EPFL Extension School, een gecertificeerd online leerplatform dat digitale vaardigheden leert in data science, ontwikkeling van webapplicaties en meer. EPFL is een van ‘ s werelds toonaangevende universiteiten en is gerangschikt de “nummer 1 jonge universiteit” door de Times Higher Education Ranking.



+