Cu ceva timp în urmă am scris un articol Încărcarea fișierelor cu șine și altar, care a explicat cum să introduci o caracteristică de încărcare a fișierelor în aplicația Rails cu ajutorul bijuteriei Shrine. Există, totuși, o grămadă de soluții similare disponibile și unul dintre preferatele mele este Dragonfly - o soluție de încărcare ușor de folosit pentru Rails and Rack creată de Mark Evans.
Am acoperit această bibliotecă la începutul anului trecut, dar, la fel ca în cazul majorității software-urilor, ajută să aruncăm o privire la biblioteci din când în când pentru a vedea ce sa schimbat și cum putem să o folosim în aplicația noastră.
În acest articol vă voi îndruma prin configurarea Dragonfly și explicați cum să utilizați principalele sale caracteristici. Veți învăța cum să:
Pentru a face lucrurile mai interesante, vom crea o mică aplicație muzicală. Acesta va prezenta albume și melodii asociate care pot fi gestionate și redate pe site.
Codul sursă pentru acest articol este disponibil la GitHub. Puteți, de asemenea, verifica demo-ul de lucru al aplicației.
Pentru a începe, creați o nouă aplicație Rails fără suita de testare implicită:
șine noi UploadingWithDragonfly -T
Pentru acest articol voi folosi Rails 5, dar majoritatea conceptelor descrise se aplică și versiunilor mai vechi.
Micul nostru site muzical va conține două modele: Album
și Cântec
. Pentru moment, să creăm primul cu următoarele câmpuri:
titlu
(şir
) - conține titlul albumuluicântăreaţă
(şir
) -albumimage_uid
(şir
) - un câmp special pentru stocarea imaginii de previzualizare a albumului. Acest câmp poate fi numit orice doriți, dar trebuie să conțină _uid
sufix conform instrucțiunilor din documentația Dragonfly.Creați și aplicați migrarea corespunzătoare:
rails g model Titlul albumului: string singer: string image_uid: string șir db: migrate
Acum, să creăm un controler generic pentru a gestiona albume cu toate acțiunile implicite:
clasa AlbumsController < ApplicationController def index @albums = Album.all end def show @album = Album.find(params[:id]) end def new @album = Album.new end def create @album = Album.new(album_params) if @album.save flash[:success] = 'Album added!' redirect_to albums_path else render :new end end def edit @album = Album.find(params[:id]) end def update @album = Album.find(params[:id]) if @album.update_attributes(album_params) flash[:success] = 'Album updated!' redirect_to albums_path else render :edit end end def destroy @album = Album.find(params[:id]) @album.destroy flash[:success] = 'Album removed!' redirect_to albums_path end private def album_params params.require(:album).permit(:title, :singer) end end
În cele din urmă, adăugați rutele:
resurse: albume
Este timpul ca Dragonfly să intre în lumina reflectoarelor. Mai întâi, adăugați bijuteria în Gemfile:
bijuterie dragonfly
Alerga:
bilele de instalare a șinelor generează dragonfly
Ultima comandă va crea un inițializator numit dragonfly.rb cu configurația implicită. O vom pune deoparte deocamdată, dar puteți citi despre diferitele opțiuni de pe site-ul oficial al Dragonfly.
Următorul lucru important care trebuie făcut este echiparea modelului nostru cu metodele Dragonfly. Acest lucru se face folosind dragonfly_accessor
:
dragonfly_accessor: imagine
Rețineți că aici vă spun :imagine
-se referă în mod direct la image_uid
care am creat în secțiunea anterioară. Dacă, de exemplu, ați denumit coloana photo_uid
, apoi dragonfly_accessor
metoda ar trebui să primească :fotografie
ca argument.
Dacă utilizați Rails 4 sau 5, un alt pas important este de a marca :imagine
câmp (nu : image_uid
!) așa cum este permis în regulator:
params.require (: album) .permite (: titlu,: cântăreață,: imagine)
Acest lucru este destul de mult - suntem gata să creăm vederi și să începem să încărcăm fișierele noastre!
Începeți cu vizualizarea index:
Albume
<%= link_to 'Add', new_album_path %>
Acum parțial:
Există două metode Dragonfly care trebuie menționate aici:
album.image.url
returnează calea spre imagine.album.image_stored?
spune dacă înregistrarea are un fișier încărcat în loc.Acum adăugați paginile noi și editați:
Adăugați un album
<%= render 'form' %>
Editați | × <%= @album.title %>
<%= render 'form' %>
<%= form_for @album do |f| %><%= f.label :title %> <%= f.text_field :title %><%= f.label :singer %> <%= f.text_field :singer %><%= f.label :image %> <%= f.file_field :image %><%= f.submit %> <% end %>
Forma nu este nimic fantezie, dar, din nou, rețineți că spunem :imagine
, nu : image_uid
, la redarea intrării fișierului.
Acum este posibil să bootați serverul și să testați caracteristica de încărcare!
Astfel, utilizatorii pot crea și edita albume, însă există o problemă: nu au nici o posibilitate să înlăture o imagine, doar să o înlocuiască cu o altă imagine. Din fericire, acest lucru este foarte ușor de rezolvat prin introducerea unei casete de eliminare a imaginii:
<% if @album.image_thumb_stored? %> <%= image_tag(@album.image.url, alt: @album.title) %> <%= f.label :remove_image %> <%= f.check_box :remove_image %> <% end %>
Dacă albumul are o imagine asociată, îl afișăm și facem o casetă de selectare. Dacă această casetă de selectare este setată, imaginea va fi eliminată. Rețineți că dacă domeniul dvs. este denumit photo_uid
, atunci metoda corespunzătoare pentru a elimina atașamentul va fi remove_photo
. Simplu, nu-i așa??
Singurul alt lucru de făcut este permisiunea remove_image
atribut în controlorul dvs.:
params.require (: album) .permite (: titlu,: cântăreață,: imagine,: remove_image)
În acest stadiu, totul funcționează bine, dar nu verificăm deloc contribuția utilizatorului, ceea ce nu este deosebit de important. Prin urmare, să adăugăm validări pentru modelul albumului:
validează: titlu, prezență: adevărat validează: cântăreț, prezență: validează adevărat: imagine, prezență: validă validates_property: width, of:: image, in:
validates_property
este metoda Dragonfly care poate verifica diferite aspecte ale atașamentului dvs.: puteți valida extensia unui fișier, tipul MIME, dimensiunea etc..
Acum, să creăm un parțial generic pentru a face erorile care au fost găsite:
<% if object.errors.any? %><% end %>Au fost găsite următoarele erori:
<% object.errors.full_messages.each do |msg| %>
- <%= msg %>
<% end %>
Utilizați acest lucru parțial în interiorul formularului:
<%= form_for @album do |f| %> <%= render 'shared/errors', object: @album %> <%#… %> <% end %>
Stilul câmpurilor cu erori un pic pentru a le vizualiza vizual:
.field_with_errors display: inline; etichetă culoare: roșu; intrare background-color: lightpink;
După introducerea validărilor, ne confruntăm cu o altă problemă (destul de scenariu tipic, eh?): Dacă utilizatorul a făcut greșeli în completarea formularului, va trebui să aleagă din nou fișierul după ce a dat clic pe A depune buton.
Dragonfly vă poate ajuta să rezolvați această problemă și cu ajutorul a retained_ *
câmp ascuns:
<%= f.hidden_field :retained_image %>
Nu uitați să permiteți și acest domeniu:
params.require (: album) .permit (: titlu,: cântăreață,: image,: remove_image,: retained_image)
Acum imaginea va fi persistenta intre cereri! Singura problemă mică este totuși faptul că intrarea de încărcare a fișierului va afișa în continuare mesajul "alegeți un fișier", dar acest lucru poate fi rezolvat cu ceva stil și o linie de JavaScript.
Imaginile încărcate de utilizatorii noștri pot avea dimensiuni foarte diferite, care pot (și probabil vor) cauza un impact negativ asupra designului site-ului. Probabil că doriți să scalați imaginile până la anumite dimensiuni fixe și, bineînțeles, acest lucru este posibil prin utilizarea lăţime
și înălţime
stiluri. Aceasta nu este, însă, o abordare optimă: browserul va trebui să descarce în continuare imagini de dimensiune completă și apoi să le micșoreze.
O altă opțiune (care este de obicei mult mai bună) este de a genera miniaturi de imagini cu unele dimensiuni predefinite pe server. Acest lucru este foarte simplu de realizat cu Dragonfly:
250x250
este, desigur, dimensiunile, în timp ce #
este geometria care înseamnă "redimensionarea și recoltarea dacă este necesar pentru a menține raportul de aspect cu gravitația centrală". Puteți găsi informații despre alte geometrii pe site-ul web Dragonfly.
deget mare
metoda este alimentată de ImageMagick - o soluție excelentă pentru crearea și manipularea imaginilor. Prin urmare, pentru a vedea demo-ul de lucru la nivel local, va trebui să instalați ImageMagick (toate platformele majore sunt suportate).
Suportul pentru ImageMagick este activat implicit în interiorul inițializatorului Dragonfly:
plugin: imaginemagic
Acum se generează miniaturi, dar acestea nu sunt stocate nicăieri. Aceasta înseamnă că de fiecare dată când un utilizator accesează pagina cu albume, miniaturile vor fi regenerate. Există două modalități de a depăși această problemă: prin generarea acestora după salvarea înregistrării sau prin efectuarea unei generații în zbor.
Prima opțiune implică introducerea unei coloane noi pentru a stoca miniaturile și pentru a le modifica dragonfly_accessor
metodă. Creați și aplicați o nouă migrare:
rails g migrație add_image_thumb_uid_to_albums image_thumb_uid: șine de șir db: migrează
Acum modificați modelul:
dragonfly_accessor: imagine face copy_to (: image_thumb) | a | a.thumb ('250x250 #') sfârșitul dragonfly_accessor: image_thumb
Rețineți că acum primul apel către dragonfly_accessor
trimite un bloc care generează de fapt thumbnail-ul pentru noi și îl copiază în image_thumb
. Acum folosiți doar image_thumb
metoda în opinia dvs.:
<%= image_tag(album.image_thumb.url, alt: album.title) if album.image_thumb_stored? %>
Această soluție este cea mai simplă, dar nu este recomandată de documentele oficiale și, ceea ce este mai rău, la momentul scrisului nu funcționează cu retained_ *
câmpuri.
Prin urmare, permiteți-mi să vă arăt o altă opțiune: generarea miniaturilor în zbor. Aceasta implică crearea unui nou model și ajustarea fișierului de configurare a Dragonfly. În primul rând, modelul:
rails g model Thumb uid: șir de caractere: string rake db: migrați
degetele
tabelul va găzdui miniaturile dvs., dar acestea vor fi generate la cerere. Pentru a face acest lucru, trebuie să redefinim URL-ul
în interiorul inițializatorului Dragonfly:
Dragonfly.app.configure do define_url do | app, job, opts | thumb = Thumb.find_by_job (job.signature) dacă thumb app.datastore.url_for (thumb.uid,: schema => 'https') altceva app.server.url_for (job) end end before_serve do | job, env | uid = job.store Thumb.create! (: uid => uid,: job => job.signature) sfârșitul # ... sfârșit
Acum adăugați un nou album și vizitați pagina rădăcină. Prima dată când o faceți, următoarea ieșire va fi tipărită în jurnale:
DRAGONFLY: comanda shell: "converti" "some_path / public / system / dragonfly / development / 2017/02/08 / 3z5p5nvbmx_Folder.jpg" "-prezentarea" "250x250 ^ 250x250 + 0 + 0 "" + repetă "" some_path / 20170208-1692-1xrqzc9.jpg "
Acest lucru inseamna ca thumbnail-ul este generat pentru noi de catre ImageMagick. Dacă reîncărcați pagina, cu toate acestea, această linie nu va mai apărea, ceea ce înseamnă că miniatură a fost stocată în cache! Puteți citi mai multe despre această funcție pe site-ul Web Dragonfly.
Puteți efectua practic orice manipulare a imaginilor după ce au fost încărcate. Acest lucru se poate face în interiorul after_assign
suna inapoi. Să transformăm, de exemplu, toate imaginile noastre în format JPEG cu o calitate de 90%:
dragonfly_accessor: imagine face după_assign | a | a.encod! ('jpg', '-quality 90') final
Există multe alte acțiuni pe care le puteți efectua: rotiți și decupați imaginile, codificați-le cu un format diferit, scrieți un text pe acestea, amestecați cu alte imagini (de exemplu, pentru a plasa un filigran) etc. Pentru a vedea alte exemple, consultați secțiunea ImageMagick de pe site-ul Dragonfly.
Bineînțeles, partea principală a site-ului nostru muzical este cântece, deci să le adăugăm acum. Fiecare melodie are un titlu și un fișier muzical și aparține unui album:
rails g model Albume album: belongs_to titlu: string track_uid: string rails db: migrate
Conectați metodele Dragonfly, așa cum am făcut pentru Album
model:
dragonfly_accessor: piesa
Nu uitați să stabiliți a are multe
relație:
has_many: melodii, dependente:: distruge
Adăugați noi rute. O cântec există întotdeauna în sfera unui album, așa că voi face aceste rute imbrăcate:
resurse: albumele fac resurse: cântece, numai: [: new,: create] end
Creați un controler foarte simplu (încă o dată, nu uitați să permiteți urmări
camp):
clasa SongsController < ApplicationController def new @album = Album.find(params[:album_id]) @song = @album.songs.build end def create @album = Album.find(params[:album_id]) @song = @album.songs.build(song_params) if @song.save flash[:success] = "Song added!" redirect_to album_path(@album) else render :new end end private def song_params params.require(:song).permit(:title, :track) end end
Afișați melodiile și un link pentru a adăuga unul nou:
<%= @album.title %>
de <%= @album.singer %>
<%= link_to 'Add song', new_album_song_path(@album) %><%= render @album.songs %>
Codul formularului:
Adăugați cântecul la <%= @album.title %>
<%= form_for [@album, @song] do |f| %><%= f.label :title %> <%= f.text_field :title %><%= f.label :track %> <%= f.file_field :track %><%= f.submit %> <% end %>
În cele din urmă, adăugați _cântec parțial:
Aici folosesc HTML5 audio
tag, care nu va funcționa pentru browserele mai vechi. Deci, dacă intenționați să sprijiniți astfel de browsere, utilizați un polifil.
După cum vedeți, întregul proces este foarte simplu. Dragonfly nu are mare grijă ce tip de fișier doriți să încărcați; tot ce trebuie să faceți este să oferiți dragonfly_accessor
, adăugați un câmp corespunzător, permiteți-l și faceți o etichetă de introducere a fișierului.
Când deschid o listă de redare, mă aștept să vadă câteva informații suplimentare despre fiecare melodie, cum ar fi durata sau frecvența de redare. Desigur, în mod implicit aceste informații nu sunt stocate nicăieri, dar putem rezolva acest lucru cu ușurință. Dragonfly ne permite să furnizăm date suplimentare despre fiecare fișier încărcat și să îl preluăm mai târziu utilizând meta
metodă.
Lucrurile sunt însă mult mai complexe atunci când lucrăm cu audio sau video, pentru că pentru a le prelua metadatele, este nevoie de un gem streamio-ffmpeg special. Această bijuterie, la rândul său, se bazează pe FFmpeg, deci pentru a continua va trebui să o instalați pe PC.
Adăuga streamio-FFMPEG
în Gemfile:
gem "streamio-ffmpeg"
Instalați-l:
instalare pachet
Acum putem folosi la fel after_assign
callback deja văzut în secțiunile anterioare:
dragonfly_accessor: urmăriți după song = FFMPEG :: Movie.new (a.path) mm, ss = melodie.duration.divmod (60) .map | n | n.to_i.to_s.rjust (2, '0') a.meta ['duration'] = "# mm: # ss" a.meta ['bitrate'] = song.bitrate? song.bitrate / 1000: 0 sfârșitul final
Rețineți că aici folosesc a cale
metoda, nu URL-ul
, pentru că în acest moment lucrăm cu un temp template. Apoi extragem durata cântecului (convertirea acestuia în minute și secunde cu zerouri în frunte) și bitrate-ul său (transformându-l în kilobytes pe secundă).
În cele din urmă, afișați metadatele în vizualizare:
Dacă verificați conținutul pe publice / sistem / Dragonfly (locația implicită pentru găzduirea încărcărilor), veți nota unele .YML fișiere - stochează toate informațiile meta în format YAML.
Ultimul subiect pe care îl vom acoperi astăzi este cum să vă pregătiți aplicația înainte de a vă deplasa la platforma cloud-ului Heroku. Principala problemă este că Heroku nu vă permite să stocați fișiere personalizate (cum ar fi încărcările), așa că trebuie să ne bazăm pe un serviciu de stocare în cloud ca Amazon S3. Din fericire Dragonfly poate fi integrat cu ușurință.
Tot ce trebuie să faceți este să înregistrați un nou cont la AWS (dacă nu îl aveți deja), să creați un utilizator cu permisiunea de a accesa coșurile S3 și să notați perechea de chei a utilizatorului într-o locație sigură. S-ar putea să utilizați o pereche de cheie rădăcină, dar asta este cu adevărat Nu se recomandă. În cele din urmă, creați o găleată S3.
Revenind la aplicația Rails, plasați o bijuterie nouă:
grup: producție gem 'dragonfly-s3_data_store' sfârșit
Instalați-l:
instalare pachet
Apoi configurați Dragonfly pentru a utiliza S3 într-un mediu de producție:
dacă Rails.env.production? datastore: s3, bucket_name: ENV ['S3_BUCKET'], acces_key_id: ENV ['S3_KEY'], secret_access_key: ENV ['S3_SECRET'], regiune: ENV ['S3_REGION'], url_scheme: root_path: Rails.root.join ('public / system / dragonfly', Rails.env), root_root: Rails.root.join ('public') sfârșitul
A furniza ENV
variabile pe Heroku, utilizați această comandă:
heroku config: adăugați SOME_KEY = SOME_VALUE
Dacă doriți să testați integrarea cu S3 local, puteți folosi o bijuterie ca dotenv-șine pentru a gestiona variabilele de mediu. Amintiți-vă, totuși, că perechea de chei AWS nu trebuie expuse public!
O altă problemă mică pe care am întâlnit-o în timpul desfășurării lui Heroku a fost absența FFmpeg. Chestia este că atunci când se creează o nouă aplicație Heroku, ea are un set de servicii care sunt utilizate în mod obișnuit (de exemplu, ImageMagick este disponibil în mod implicit). Alte servicii pot fi instalate ca addons Heroku sau sub forma de buildpacks. Pentru a adăuga un pachet de construcție FFmpeg, executați următoarea comandă:
pachete de construcție heroku: adăugați https://github.com/HYPERHYPER/heroku-buildpack-ffmpeg.git
Acum totul este gata, și puteți împărtăși aplicația dvs. muzicală cu lumea!
A fost o călătorie lungă, nu-i așa? Astăzi am discutat despre Dragonfly - o soluție pentru încărcarea fișierelor în Rails. Am văzut setarea de bază, unele opțiuni de configurare, generarea de miniaturi, prelucrarea și stocarea metadatelor. De asemenea, am integrat Dragonfly cu serviciul Amazon S3 și am pregătit aplicația noastră pentru implementare pe producție.
Desigur, nu am discutat despre toate aspectele Dragonfly în acest articol, deci asigurați-vă că navigați pe site-ul său oficial pentru a găsi o documentație extensivă și exemple utile. Dacă aveți alte întrebări sau sunteți blocat (ă) de câteva exemple de cod, nu ezitați să mă contactați.
Vă mulțumim că ați rămas cu mine și vă voi vedea în curând!