trecerea de la CarrierWave la ActiveStorage într-o aplicație Rails

NJ Pearman
NJ Pearman

urmați

Jun 20 · 2018 * 9 min citit

folosim Ruby on Rails pentru a preda dezvoltarea aplicațiilor web la școala de extensii EPFL. Este un cadru excelent, solid, încercat și de încredere și prezintă o structură ușor de urmărit atunci când faceți primii pași învățând despre dezvoltarea web.

dar este, de asemenea, o piesă de software în continuă evoluție, cu îmbunătățiri și noi caracteristici fiind lansate în fiecare an. Una dintre adăugările recente la Rails în versiunea 5.2 Este caracteristica ActiveStorage, care adaugă pentru prima dată gestionarea ușoară a încărcării fișierelor în cadrul Core Rails.

în prima iterație a programului nostru de dezvoltare a aplicațiilor web, includem un subiect pentru a afla cum să adăugați încărcări de fișiere într-o aplicație Rails. Cu toate acestea, folosim Rails 5.1 în program, iar subiectul de încărcare a fișierelor folosește una dintre soluțiile terțe utilizate pe scară largă pentru adăugarea încărcărilor de fișiere, numită CarrierWave. Aceasta este o bijuterie solidă terță parte care ne permite să implementăm încărcări de fișiere într-o aplicație Rails și este utilizată în multe aplicații Ruby on Rails din lumea reală — inclusiv platforma noastră de cursant!

dar odată cu introducerea ActiveStorage, aceste pietre terțe devin mai puțin atractive decât această nouă soluție inclusă în interiorul șinelor. De fapt, Paperclip, una dintre celelalte pietre Populare de încărcare a fișierelor terțe, a anunțat deja că este depreciată în favoarea ActiveStorage. Dezvoltatorii Paperclip au recunoscut că ActiveStorage este o alegere mai bună pentru dezvoltatori și au încetat să mai lucreze la propria bijuterie.

deci, să ne uităm în mod specific la ceea ce este nevoie pentru a trece de la CarrierWave în Rails 5.1 la ActiveStorage în Rails 5.2.

aplicația

în programul de dezvoltare a aplicațiilor web, lucrăm prin construirea unei aplicații web numită My Bucket List. Aceasta este o aplicație care permite utilizatorilor să creeze și să urmărească experiențe pe care și-au dorit întotdeauna să le realizeze. Utilizatorii pot vedea ce au creat alte persoane și le pot urmări și pe acestea. Una dintre caracteristicile din aplicație permite unui utilizator să-și încarce propriul avatar și construim această caracteristică pentru a afla despre încărcările de fișiere și atașamentele folosind CarrierWave.

un utilizator poate încărca un avatar cu acest formular, folosind CarrierWave

deci, în primul rând, să aibă o scurtă trecere în revistă a ceea ce este implicat cu adăugarea unui atașament simplu folosind CarrierWave.

configurație CarrierWave

pentru a include CarrierWave într-un proiect, trebuie să:

  • adăugați bijuteria CarrierWave la Gemfile.
  • includeți adaptorul CarrierWave pentru ActiveRecord într-un inițializator de configurare, config/initializers/carrierwave.rb.

și apoi pentru a adăuga un atașament imagine la un model, trebuie să:

  • generați un Uploader folosind rails generate uploader UploaderName.
  • adăugați un atribut pe model pentru a stoca numele de fișier atașat pentru fiecare înregistrare, cu migrarea bazei de date asociate.
  • editați valorile din uploader, cum ar fi locația de stocare a încărcării și imaginea implicită.
  • utilizați macrocomanda mount_uploader din model pentru a include încărcătorul particular.
  • adăugați un câmp de formular de fișier în care poate fi încărcată o imagine.
  • adăugați atributul model la lista de parametri puternici din controlerul care gestionează formularul care conține câmpul Fișier.

să luăm în considerare unul dintre aceste puncte în continuare: în CarrierWave, este necesar să adăugați atribute specifice oricărui model care trebuie să aibă un fișier atașat. De exemplu, un model User care are nevoie de o imagine avatar atașată la acesta va avea nevoie de un atribut numit :avatar care este String. Aceasta necesită o migrare a bazei de date pentru a adăuga coloana bazei de date subiacente, plus crearea și montarea unei clase Uploader la acel atribut din model.

acest lucru nu este deosebit de laborios, dar, după cum vom vedea, ActiveStorage necesită mult mai puțin cod de la caz la caz.

încă un punct de subliniat este că în aplicația mea — Aplicația My Bucket List — încărcătorul CarrierWave avatar este configurat cu stocarea implicită a fișierelor simple. În ordinea cuvintelor, imaginile încărcate sunt stocate undeva în folderul public/ din aplicație. Această cale precisă este definită în clasa Uploaderpentru avatar și este setată la "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}". Aceasta este o cale relativă la folderul public/, astfel încât imaginile încărcate să fie accesibile direct prin serverul web. Acest lucru permite accesul direct la fișierele de atașament, pe care le putem contrasta cu ActiveStorage mai târziu.

modernizarea șinelor

înainte de a analiza ActiveStorage, este necesar să faceți upgrade la șinele 5.2. Aceasta este o sarcină care poate fi destul de implicată, în funcție de complexitatea aplicației dvs. Aplicația pe care o folosesc aici, pe care o construim în programul nostru WAD, nu este deosebit de dificil de actualizat, dar are încă nevoie de îngrijire și atenție.

Iată ce am făcut pentru a actualiza aplicația My Bucket List de la Rails 5.1 la Rails 5.2.

în primul rând, am creat o nouă sucursală în depozitul meu git pentru a izola actualizarea — este important să puteți reveni la versiunea anterioară de lucru a unei aplicații dacă ceva nu merge bine în procesul de actualizare!

pe noua ramură, am schimbat versiunea de șine în Gemfile de la '~> 5.1.2' la '~> 5.2.0', și apoi a fugit bin/bundle update rails — această comandă descarcă noua versiune a rails și toate pietre legate în cerere. Pentru cererea mea, nu au existat conflicte gem, dar dacă utilizați pietre terțe părți, ar putea fi necesar pentru a rezolva conflictele dintre diferite versiuni gem în acest moment!

după instalarea noului Rails gem și dependențele sale, este necesar să actualizați aplicația în sine. Am făcut acest lucru folosind bin/bundle exec rails app:update. Această comandă actualizează programatic toate fișierele necesare din aplicație pentru a lucra cu Rails 5.2.

dar… această comandă va suprascrie modificările pe care le-ați făcut aplicației dvs., cum ar fi config/routes.rb. Din fericire, comanda întreabă dacă să suprascrie fiecare fișier și este posibil să diff oricare dintre aceste fișiere în timpul acestui proces pentru a verifica ce ar fi suprascris. Promptul pentru fiecare suprascriere este , ceea ce înseamnă:

  • Y pentru „Da, suprascrie fișierul meu” și este opțiunea implicită dacă apăsați doar Enter.
  • n pentru „nu, nu suprascrie fișierul meu”
  • a pentru ” Da, suprascrie acest fișier și suprascrie orice alt fișier prea!”. (Regula mea generală este să nu folosiți niciodată a).
  • q pentru „părăsiți acest proces”
  • d pentru „Arată-mi diferențele dintre fișierul meu și suprascriere”
  • h pentru ” Arată-mi o listă a ceea ce înseamnă Ynaqdh

în cererea mea, am acceptat fiecare suprascriere cu Y cu excepția config/routes.rb și config/locales/en.yml. Aceste două fișiere erau fișiere pe care le schimbasem și așa am vrut să-mi păstrez versiunea, așa că am ales n.

acest proces de actualizare ar putea fi mai implicat dacă aveți o aplicație mai complexă, în special dacă aveți o mulțime de configurații personalizate în oricare dintre fișierele de configurare a mediului, adică. config/environments/production.rb, config/environments/test.rb și config/environments/development.rb. Actualizarea adaugă setări importante acestor fișiere, dar veți dori, de asemenea, să vă păstrați propria configurație personalizată — aici vă ajută să aveți versiunea originală a aplicației într-o ramură git separată. Apoi, este posibil ca codul din această ramură veche să verifice dacă tot codul și configurația aplicației dvs. sunt încă în vigoare după actualizare.

după rularea bin/bundle exec rails app:update, a fost necesar să adaug bijuteria bootsnapla Gemfile. Aceasta este o nouă bijuterie utilizată în Rails 5.2, dar nu este adăugată ca parte a comenzii app:upgrade. Așa că am adăugat gem 'bootsnap' la Gemfileși apoi am rulat bin/bundle install.

după aceasta, aplicația mea Bucket List a început ca înainte de a utiliza rails server.

înlocuirea CarrierWave cu ActiveStorage

deci, cu aplicația care rulează acum pe șine 5.2, aș putea începe înlocuirea CarrierWave cu ActiveStorage.

cu ActiveStorage, nu este necesar să adăugați atribute specifice modelului pentru a stoca numele de fișiere atașate care sunt necesare cu CarrierWave. ActiveStorage funcționează cu aceleași două tabele asociate pentru toate atașamentele.

pentru a configura aceste două tabele, am rulat bin/bundle exec rails active_storage:installurmat de rails db:migrate. Cele două tabele sunt active_storage_blobs și active_storage_attachments; primul este pentru detaliile fișierului atașat, iar al doilea este pentru tabelul de îmbinare polimorfă care leagă un fișier atașat de o înregistrare model.

și aici este punctul important: odată ce am creat aceste două tabele, nu avem nevoie pentru a crea orice alte migrații pentru a include atașamente în modelele noastre! Acest lucru face ActiveStorage ușor de a lucra cu dintr-o perspectivă de bază de date.

apoi, m-am uitat la înlocuirea implementării atașamentului :avatar cu ActiveStorage în loc de CarrierWave. În aplicația mea, fiecare Userare un :avatar. Pentru că am fost folosind CarrierWave anterior, am avut un :avatar atribut montat la un CarrierWave Uploader în User modelul, a declarat ca aceasta:

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

atașamentul CarrierWave :avatar poate fi înlocuit cu un atașament ActiveSupport utilizând has_one_attached :avatar, astfel:

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

aceasta este o modificare a unei linii de cod. În acest moment, ce altceva trebuie făcut? De exemplu, cum este setată locația de stocare a încărcării? Amintiți-vă că în aplicația mea, încărcătorul avatar CarrierWave este configurat cu stocarea simplă implicită a fișierelor, iar locația pentru aceasta este setată Explicit în fișierul avatar_uploader.rb. Stocarea simplă a fișierelor este implicită și în ActiveStorage. Locația este setată în fișierul config/storage.yml, cu o valoare implicită pentru încărcările locale.

configurarea implicită pentru ActiveStorage înseamnă că nu mai trebuie să scriu niciun cod pentru încărcările mele pentru a funcționa pentru atributul :avatar modificat din aplicația mea. Am schimbat mecanismul de încărcare în întregime de la CarrierWave la ActiveStorage și nu trebuie să fac nimic mai mult: Nu trebuie să fac modificări controlerului care gestionează încărcarea, deoarece :avatar este deja declarat ca un parametru puternic. Și nu trebuie să schimb câmpul de formular de fișier în vizualizarea care permite utilizatorilor să selecteze o imagine de încărcat, deoarece aceasta este susținută de :avatar „atribut”.

dar există încă o schimbare pe care trebuie să o fac pentru a migra de la CarrierWave la ActiveStorage și acesta este modul de utilizare a imaginii atașate în vizualizări. Cu CarierWave, am folosit metoda avatar_url pentru a reda calea completă a imaginii. Cu ActiveStorage, URL-ul fișierului nu este randat din atributul atașament în sine, ci randat prin trecerea atributului la metodele helper. Deci, URL-ul atașamentului complet poate fi randat folosind url_for(user.avatar) sau direct cu image_tag.

de asemenea, este necesar să verificați în mod explicit dacă atașamentul este prezent, astfel încât o utilizare completă într-o vizualizare ar arăta cam așa:

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

odată ce am actualizat referințele la user.avatar_url în opiniile mele cu fragmente de genul acesta de mai sus, m-am mutat complet de la CarrierWave la ActiveStorage pentru toate încărcările noi.

Vechiul Cod CarrierWave trebuie să fie ordonat și există o întrebare despre ce să facem cu încărcările existente care au fost făcute cu CarrierWave. Dar vedeți mai jos despre asta…

scenarii mai complexe

aproape toate scenariile de producție vor fi mai complexe decât cele prezentate mai sus. Va fi necesar să luați în considerare lucruri precum încărcările stocate pe CDN-uri sau servere la distanță precum AWS S3 și redimensionarea imaginilor pentru miniaturi etc. ActiveStorage ne permite să facem o mulțime de aceste lucruri din cutie prea și pare foarte bine proiectat pentru nevoile dezvoltatorilor. După cum v-ați putea aștepta, există o documentație bună în Ghidul Rails.

în ceea ce privește migrarea încărcărilor existente de la CarrierWave la ActiveStorage, acest lucru ar fi cu siguranță posibil cu un script rake relativ mic. Voi urmări să acopere că într-un post viitor.

acesta a fost un scenariu simplu, dar în general am fost foarte mulțumit de cât de ușor a fost să folosiți ActiveStorage și să înlocuiți CarrierWave cu acesta. De asemenea, îmi place gândul care a intrat în diferitele părți ale ActiveStorage, deoarece totul pare să fie în fișiere și foldere care se potrivesc frumos cu structura restului șinelor. Cu siguranță cred că merită să intrați în Rails 5.2 pentru a utiliza ActiveStorage pentru încărcări de fișiere în aplicațiile dvs.!

Aflați mai multe!

vrei să afli mai multe despre Ruby și Ruby on Rails? Predau dezvoltarea aplicațiilor Web la EPFL Extension School, o platformă de învățare online certificată care predă abilități digitale în știința datelor, Dezvoltarea aplicațiilor web și multe altele. EPFL este una dintre cele mai importante universități din lume și este clasată „Universitatea tânără numărul 1” de către Times Higher Education Ranking.



+