Încărcarea cu rails și Carrierwave

Acesta este un alt articol din seria "Încărcarea cu șine". Astăzi vom întâlni Carrierwave - una dintre cele mai populare soluții de încărcare a fișierelor pentru Rails. Îmi place Carrierwave, deoarece este ușor să începeți, are o mulțime de caracteristici din cutie și oferă zeci de articole "cum să" scrise de membrii comunității, astfel încât să nu vă pierdeți.

În acest articol, veți învăța cum să:

  • Integrați Carrierwave în aplicația Rails
  • Adăugați validări
  • Păstrați fișierele între solicitări
  • Eliminați fișierele
  • Generați miniaturi
  • Încărcați fișiere din locații îndepărtate
  • Introduceți mai multe încărcări de fișiere
  • Adăugați suport pentru stocarea în cloud

Codul sursă pentru acest articol este disponibil pe GitHub. Bucură-te de lectură!

Poziționarea fundațiilor

Ca întotdeauna, începeți prin crearea unei noi aplicații Rails:

șine noi UploadingWithCarrierwave -T

Pentru acest demo voi folosi Rails 5.0.2. Rețineți că Carrierwave 1 acceptă numai Rails 4+ și Ruby 2. Dacă sunteți în continuare de echitatie pe Rails 3, apoi cârlig Carrierwave versiunea 0.11.

Pentru a vedea Carrierwave în acțiune, vom crea o aplicație de bloguri foarte simplă cu unic Post model. Acesta va avea următoarele atribute principale:

  • titlu (şir)
  • corp (text)
  • imagine (şir) - acest câmp va conține o imagine (numele unui fișier, pentru a fi exact) atașat postului

Generați și aplicați o nouă migrare:

rails g model Titlul postului: body string: text image: string rails db: migrate

Creați câteva rute:

config / routes.rb

resurse: postări rădăcină la: 'posts # index'

De asemenea, creați un controler de bază:

posts_controller.rb

clasa PostsController < ApplicationController before_action :set_post, only: [:show, :edit, :update] def index @posts = Post.order('created_at DESC') end def show end def new @post = Post.new end def create @post = Post.new(post_params) if @post.save redirect_to posts_path else render :new end end def edit end def update if @post.update_attributes(post_params) redirect_to post_path(@post) else render :edit end end private def post_params params.require(:post).permit(:title, :body, :image) end def set_post @post = Post.find(params[:id]) end end

Acum hai să construim index vedere:

vizualizari / posturi / index.html.erb

Mesaje

<%= link_to 'Add post', new_post_path %> <%= render @posts %>

Și parțial corespondent:

vizualizari / posturi / _post.html.erb

<%= link_to post.title, post_path(post) %>

<%= truncate(post.body, length: 150) %>

<%= link_to 'Edit', edit_post_path(post) %>


Aici folosesc Rails-ul trunchia pentru a afișa numai primele 150 de simboluri din post. Înainte de a crea alte vederi și o formă parțială, să integrăm mai întâi Carrierwave în aplicație.

Integrarea undelor Carrier

Puneți într - o bijuterie nouă în Gemfile:

Gemfile

gem 'carrierwave', '~> 1.0'

Alerga:

instalare pachet

Carrierwave își stochează configurația în interior uploaderi care sunt incluse în modelele dvs. Pentru a genera un încărcător, utilizați următoarea comandă:

șinele generează imaginea încărcătorului

Acum, înăuntru app / uploaderi, veți găsi un nou fișier numit image_uploader.rb. Rețineți că aceasta conține câteva comentarii și exemple utile, astfel încât să puteți folosi pentru a începe. În acest demo vom folosi ActiveRecord, dar Carrierwave are, de asemenea, suport pentru Mongoid, Sequel și DataMapper.

Apoi, trebuie să includeți sau montură acest încărcător în model:

modele / post.rb

mount_uploader: imagine, ImageUploader

Încărcătorul are deja setări prestabilite, dar cel puțin trebuie să alegem unde vor fi stocate fișierele încărcate. Pentru moment, să folosim stocarea fișierelor:

uploaderi / image_uploader.rb

stocare: fișier

Implicit, fișierele vor fi plasate în interiorul publice / încărcări directorul, deci cel mai bine este să-l excludeți de la sistemul de control al versiunilor:

.gitignore

publice / încărcări

Puteți, de asemenea, modifica store_dir în interiorul dispozitivului dvs. de încărcare pentru a alege o altă locație.

În acest moment, putem crea o vizualizare nouă și o formă parțială pentru a începe încărcarea fișierelor:

vizualizari / posturi / new.html.erb

Adăugați un post

<%= render 'form', post: @post %>

vizualizari / posturi / _form.html.erb

<%= form_for post do |f| %> 
<%= f.label :title %> <%= f.text_field :title %>
<%= f.label :body %> <%= f.text_area :body %>
<%= f.label :image %> <%= f.file_field :image %>
<%= f.submit %> <% end %>

Rețineți că PostsController nu trebuie modificată așa cum am permis deja imagine atribut.

În cele din urmă, creați vizualizarea editare:

vizualizari / posturi / edit.html.erb

Editează postarea

<%= render 'form', post: @post %>

Asta e! Este posibil să bootați serverul și să încercați să creați o postare cu o imagine. Problema este că această imagine nu este vizibilă nicăieri, deci trecem la următoarea secțiune și adăugăm o pagină de prezentare!

Afișarea imaginilor

Așadar, singura viziune pe care nu am creat-o încă este spectacol. Adăugați-l acum:

vizualizari / posturi / show.html.erb

<%= link_to 'All posts', posts_path %> 

<%= @post.title %>

<%= image_tag(@post.image.url, alt: 'Image') if @post.image? %>

<%= @post.body %>

<%= link_to 'Edit', edit_post_path(@post) %>

După cum puteți vedea, afișarea unui atașament este foarte ușoară: tot ce trebuie să faceți este să spuneți @ post.image.url pentru a apuca adresa URL a unei imagini. Pentru a obține o cale către fișier, utilizați current_path metodă. Rețineți că Carrierwave furnizează, de asemenea, o imagine? metoda pentru a verifica dacă un atașament este prezent deloc ( imagine metoda însăși nu se va mai întoarce niciodată zero, chiar dacă fișierul nu este prezent).

Acum, după ce navigați la un post, ar trebui să vedeți o imagine, dar ar putea părea prea mare: la urma urmei, nu restricționăm dimensiunile oriunde. Bineînțeles, am fi putut scala imaginea în jos cu niște reguli CSS, dar este mult mai bine să generăm o miniatură după ce fișierul a fost încărcat. Acest lucru, totuși, necesită pași suplimentari.

Generarea de miniaturi

Pentru a cultiva și a scala imagini, avem nevoie de un instrument separat. Out of the box Carrierwave are suport pentru pietrele RMagick și MiniMagick care, la rândul lor, sunt folosite pentru a manipula imaginile cu ajutorul ImageMagick. ImageMagick este o soluție open-source care vă permite să editați imagini existente și să generați altele noi, deci înainte de a continua trebuie să le descărcați și să le instalați. Apoi, aveți libertatea de a alege oricare dintre cele două pietre prețioase. Voi rămâne cu MiniMagick, deoarece este mult mai ușor de instalat și are un suport mai bun: 

Gemfile

gem 'mini_magick'

Alerga:

instalare pachet

Apoi includeți MiniMagick în încărcătorul dvs.:

uploaderi / image_uploader.rb

include CarrierWave :: MiniMagick

Acum, pur și simplu, trebuie să introducem o versiune nouă încărcătorului nostru. Conceptul de versiuni (sau stiluri) este utilizat în multe biblioteci de încărcare de fișiere; înseamnă pur și simplu că fișierele suplimentare bazate pe atașamentul original vor fi create cu, de exemplu, diferite dimensiuni sau formate. Introduceți o nouă versiune numită deget mare:

uploaderi / image_uploader.rb

versiune: degetul mare face procesul de resize_to_fill: [350, 350] sfârșit

Poate aveți la fel de multe versiuni pe care le doriți și, mai mult, versiunile pot fi chiar construite pe lângă celelalte:

uploaderi / image_uploader.rb

versiune: small_thumb, from_version:: degetul mare face process resize_to_fill: [20, 20] end

Dacă ați încărcat deja unele imagini, nu vor fi disponibile miniaturi. Aceasta nu este o problemă, totuși, deoarece le puteți re-crea din consola Rails:

ramele c Post.find_each | post | post.image.recreate_versions! (: thumb) dacă post.image?

În cele din urmă, afișați miniatură cu un link spre imaginea originală:

vizualizari / posturi / show.html.erb

<%= link_to(image_tag(@post.image.thumb.url, alt: 'Image'), @post.image.url, target: '_blank') if @post.image? %> 

Porniți serverul și observați rezultatul!

Adăugarea de validări

În prezent, încărcarea noastră funcționează, dar nu validăm informațiile despre utilizatori, ceea ce este, desigur, rău. Atâta timp cât vrem să lucrăm numai cu imagini, să lăsăm în alb lista extensiilor .png, .jpg și .gif:

uploaderi / image_uploader.rb

def extensie_whitelist% w (jpg jpeg gif png) sfârșit

De asemenea, puteți adăuga verificări pentru tipul de conținut prin definirea unui content_type_whitelist metodă:

uploaderi / image_uploader.rb

def content_type_whitelist / image \ / end

Alternativ, este posibilă listarea neagră a unor tipuri de fișiere, de exemplu executabile, prin definirea content_type_blacklist metodă.

În afară de verificarea tipului și a extensiei unui fișier, lăsați-o să fie mai mică de 1 megabyte. Pentru a face acest lucru, vom solicita o validare suplimentară a fișierelor de bijuterii pentru ActiveModel:

Gemfile

gem "file_validators"

Instalați-l:

instalare pachet

Acum, introduceți validările dorite (rețineți că adaug, de asemenea, verificări pentru titlu și corp atribute):

modele / post.rb

validează: titlu, prezență: adevărat, lungime: minimum: 2 validează: corp, prezență: valid valide: imagine, file_size: less_than: 1.megabytes

Următorul lucru de făcut este să adăugați traduceri I18n pentru mesajele de eroare ale lui Carrierwave:

config / locales / en.yml

en: erori: mesaje: carrierwave_processing_error: "Nu se poate redimensiona imaginea". carrierwave_integrity_error: "Nu o imagine." carrierwave_download_error: "Imaginea nu a putut fi descărcată". extension_whitelist_error: "Nu aveți permisiunea de a încărca fișierele% extension, tipurile admise:% allowed_types" extension_blacklist_error: "Nu aveți permisiunea de a încărca fișiere% extension, tipuri interzise:% prohibited_types"

În prezent, nu afișăm erori de validare oriunde, deci să creăm o partajare partajată:

vizualizari / partajate / _errors.html.erb

<% if object.errors.any? %> 

Au fost găsite unele erori:

    <% object.errors.full_messages.each do |message| %>
  • <%= message %>
  • <% end %>
<% end %>

Utilizați acest lucru parțial în interiorul formularului:

vizualizari / posturi / _form.html.erb

<%= render 'shared/errors', object: post %>

Acum încercați să încărcați unele fișiere nevalide și observați rezultatul. Ar trebui să funcționeze, dar dacă alegeți un fișier valid și nu completați titlul sau corpul, atunci verificările vor eșua și va apărea o eroare. Cu toate acestea, câmpul fișierului va fi șters și utilizatorul va trebui să aleagă din nou imaginea, ceea ce nu este foarte convenabil. Pentru ao remedia, trebuie să adăugăm un alt câmp la formular.

Fișiere persistente între cereri

Fișierele persistente în redisplay-urile de formă sunt de fapt destul de ușor. Tot ce trebuie să faceți este să adăugați un nou câmp ascuns și să îl permiteți în interiorul controlerului:

vizualizari / partajate / _form.html.erb

<%= f.label :image %> <%= f.file_field :image %>
<%= f.hidden_field :image_cache %>

posts_controller.rb

params.require (: post) .permite (: titlu,: corp, imagine, imagine_cache)

Acum image_cache vor fi populate automat și imaginea nu va fi pierdută. Poate fi util să afișați și o miniatură, astfel încât utilizatorul să înțeleagă că imaginea a fost procesată cu succes: 

vizualizari / partajate / _form.html.erb

<% if post.image? %> <%= image_tag post.image.thumb.url %> <% end %>

Eliminarea imaginilor

O altă caracteristică foarte comună este capacitatea de a elimina fișiere atașate la editarea unei înregistrări. Cu Carrierwave, implementarea acestei funcții nu este o problemă. Adăugați o nouă casetă de selectare în formular:

vizualizari / partajate / _form.html.erb

<% if post.image? %> <%= image_tag post.image.thumb.url %> 
<%= label_tag :remove_image do %> Eliminați imaginea <%= f.check_box :remove_image %> <% end %>
<% end %>

Și permiteți-i remove_image atribut:

posts_controller.rb

params.require (: post) .permite (: titlu,: corp,: imagine,: remove_image,: image_cache)

Asta e! Pentru a elimina manual imaginea, utilizați remove_image! metodă:

@ post.remove_image!

Încărcarea dintr-o locație la distanță

Carrierwave oferă, de asemenea, o caracteristică foarte interesantă din cutie: abilitatea de a încărca fișiere din locații îndepărtate prin URL-ul lor. Să prezentăm această abilitate acum prin adăugarea unui câmp nou și permițând atributul corespunzător: 

vizualizari / partajate / _form.html.erb

<%= f.text_field :remote_image_url %> Introduceți URL-ul unei imagini

posts_controller.rb

params.require (: post) .permite (: titlu,: body,: image,: remove_image,: image_cache,: remote_image_url)

Cat de tare e asta? Nu este nevoie să faceți nicio modificare și puteți testa imediat această caracteristică!

Lucrul cu încărcări multiple

Să presupunem că dorim ca postul nostru să aibă mai multe atașamente disponibile. Cu configurarea actuală nu este posibil, dar, din fericire, Carrierwave susține un astfel de scenariu, de asemenea. Pentru a implementa această caracteristică, trebuie să adăugați un câmp serializat (pentru SQLite) sau un câmp JSON (pentru Postgres sau MySQL). Prefer cea de-a doua opțiune, așa că acum trecem la un nou adaptor de bază de date. Îndepărtați gemul sqlite3 din Gemfile și adăugați pg în schimb:

Gemfile

gem "pg"

Instalați-l:

instalare pachet

Modificați configurația bazei de date astfel:

config / database.yml

implicit: & adaptor implicit: postgresql piscină: 5 timeout: 5000 dezvoltare: <<: *default database: upload_carrier_dev username: 'YOUR_USER' password: 'YOUR_PASSWORD' host: localhost

Creați baza de date Postgres corespunzătoare, apoi generați și aplicați migrarea:

rails g migrare add_attachments_to_posts atașamente: json rails db: migrate

Dacă preferați să respectați SQLite, urmați instrucțiunile din documentația Carrierwave.

Acum, montați încărcătoarele (rețineți forma plurală):

Modelul / post.rb

mount_uploaders: attachments, ImageUploader

Folosesc același uploader pentru atașamente, dar, desigur, puteți genera unul nou cu o configurație diferită.

Adăugați câmpul cu mai multe fișiere în formularul dvs.:

vizualizari / partajate / _form.html.erb

<%= f.label :attachments %> <%= f.file_field :attachments, multiple: true %>

Atâta timp cât atașamente câmpul va conține o matrice, ar trebui permisă în felul următor:

posts_controller.rb

params.require (: post) .permit (: title,: body, image, remove_image, image_cache, remote_image_url, attachments: []

În cele din urmă, puteți repeta atașamentele postării și le puteți afișa ca de obicei:

vizualizari / partajate / show.html.erb

<% if @post.attachments? %> 
    <% @post.attachments.each do |attachment| %>
  • <%= link_to(image_tag(attachment.thumb.url, alt: 'Image'), attachment.url, target: '_blank') %>
  • <% end %>
<% end %>

Rețineți că fiecare atașament va avea o miniatură așa cum este configurată în versiunea noastră ImageUploader. Frumos!

Utilizarea spațiului de stocare în Cloud

Lipirea cu stocarea fișierelor nu este întotdeauna convenabilă și / sau posibilă, deoarece, de exemplu, pe Heroku nu este posibilă stocarea de fișiere personalizate. Prin urmare, s-ar putea să întrebați cum să vă căsătoriți cu Carrierwave cu spațiul de stocare Amazon S3? Ei bine, este și o sarcină destul de ușoară. Carrierwave depinde de gem-aws bijuterie pentru a pune în aplicare această caracteristică:

Gemfile

bijuterie "ceata-aws"

Instalați-l:

instalare pachet

Să creați un inițializator pentru Carrierwave și să configurați stocarea cloud la nivel global:

config / initializatori / carrierwave.rb

CarrierWave.configure do | config | config.fog_provider = 'fog / aws' config.fog_credentials = furnizor: 'AWS', aws_access_key_id: ENV ['S3_KEY'], aws_secret_access_key: ENV ['S3_SECRET'], regiune: ENV ['S3_REGION'], config. fog_directory = ENV ['S3_BUCKET'] sfârșit

Există și alte opțiuni disponibile, care pot fi găsite în documentație.

Folosesc gheața Dotenv-Rail pentru a seta variabilele de mediu într-un mod sigur, dar puteți alege orice altă opțiune. Cu toate acestea, asigurați-vă că perechea de chei S3 nu este disponibilă public, deoarece altfel oricine poate încărca ceva în galeata dvs.!

Apoi, înlocuiți stocare: fișier line cu:

uploaderi / image_uploader.rb

depozitare: ceață

În afară de S3, Carrierwave acceptă încărcări în Google Storage și Rackspace. Aceste servicii sunt ușor de configurat, de asemenea.

Concluzie

Asta este pentru ziua de azi! Am acoperit toate caracteristicile majore ale Carrierwave, iar acum puteți să o utilizați în proiectele dvs. Dispune de câteva opțiuni suplimentare, așa că răsfoiți documentația.

Dacă sunteți blocați, nu ezitați să vă postați întrebările. De asemenea, ar putea fi util să aruncăm o privire asupra wiki-ului Carrierwave, care găzduiește articole "cum să" să răspundă la multe întrebări frecvente.

Deci vă mulțumesc că ați rămas împreună cu mine și că ați fost fericit de codat!

Cod