Questo è un altro articolo nella serie "Uploading with Rails". Oggi incontreremo Carrierwave, una delle soluzioni di upload di file più popolari per Rails. Mi piace Carrierwave perché è facile da iniziare, ha molte funzionalità pronte all'uso e fornisce dozzine di articoli "how to" scritti dai membri della community, quindi non ti perderai.
In questo articolo, imparerai come:
Il codice sorgente per questo articolo è disponibile su GitHub. Buona lettura!
Come sempre, inizia creando una nuova applicazione Rails:
rota nuovo UploadingWithCarrierwave -T
Per questa demo userò Rails 5.0.2. Tieni presente che Carrierwave 1 supporta solo Rails 4+ e Ruby 2. Se stai ancora utilizzando Rails 3, collega la versione 0.1 di Carrierwave.
Per vedere Carrierwave in azione, creeremo un'applicazione di blogging molto semplice con una suola Inviare
modello. Avrà i seguenti attributi principali:
titolo
(stringa
)corpo
(testo
)Immagine
(stringa
): questo campo contiene un'immagine (il nome di un file, per la precisione) collegato al postGenera e applica una nuova migrazione:
rails g model Titolo del post: string body: text image: string rails db: migrate
Imposta alcuni percorsi:
risorse: pubblica la radice su: 'posts # index'
Inoltre, crea un controller di base:
classe 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
Ora realizziamo il indice vista:
Messaggi
<%= link_to 'Add post', new_post_path %> <%= render @posts %>
E il corrispondente parziale:
<%= link_to post.title, post_path(post) %>
<%= truncate(post.body, length: 150) %>
<%= link_to 'Edit', edit_post_path(post) %>
Qui sto usando i Rails troncare
metodo per visualizzare solo i primi 150 simboli dal post. Prima di creare altre viste e un modulo parziale, in primo luogo integrare Carrierwave nell'applicazione.
Inserisci una nuova gemma nel Gemfile:
gem 'carrierwave', '~> 1.0'
Correre:
installazione bundle
Carrierwave memorizza la sua configurazione all'interno uploaders che sono inclusi nei tuoi modelli. Per generare un uploader, utilizzare il seguente comando:
rails genera immagine uploader
Ora, dentro app / uploaders, troverai un nuovo file chiamato image_uploader.rb. Nota che ha alcuni commenti ed esempi utili, quindi puoi usarlo per iniziare. In questa demo useremo ActiveRecord, ma Carrierwave ha anche il supporto per Mongoid, Sequel e DataMapper.
Successivamente, dobbiamo includere o montare questo uploader nel modello:
mount_uploader: image, ImageUploader
L'uploader ha già impostazioni predefinite, ma per lo meno dobbiamo scegliere dove archiviare i file caricati. Per ora, utilizziamo lo spazio per i file:
archiviazione: file
Per impostazione predefinita, i file verranno posizionati all'interno di pubblici / uploads directory, quindi è meglio escluderla dal sistema di controllo della versione:
pubblici / uploads
È inoltre possibile modificare il store_dir
metodo all'interno del tuo uploader per scegliere un'altra posizione.
A questo punto, possiamo creare una nuova vista e un modulo parziale per iniziare a caricare i file:
Aggiungi post
<%= render 'form', post: @post %>
<%= 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 %>
Si noti che il PostsController
non ha bisogno di essere modificato in quanto abbiamo già permesso il Immagine
attributo.
Infine, crea la vista di modifica:
Modifica post
<%= render 'form', post: @post %>
Questo è tutto! Puoi avviare il server e provare a creare un post con un'immagine. Il problema è che questa immagine non è visibile da nessuna parte, quindi passiamo alla sezione successiva e aggiungiamo una pagina di presentazione!
Quindi, l'unica vista che non abbiamo ancora creato è mostrare. Aggiungilo ora:
<%= 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) %>
Come puoi vedere, la visualizzazione di un allegato è davvero semplice: tutto quello che devi fare è dire @ post.image.url
per prendere l'URL di un'immagine. Per ottenere un percorso per il file, utilizzare il current_path
metodo. Si noti che Carrierwave fornisce anche un Immagine?
metodo per noi per verificare se un allegato è presente a tutti (il Immagine
il metodo stesso non tornerà mai più zero
, anche se il file non è presente).
Ora, dopo aver navigato in un post, dovresti vedere un'immagine, ma potrebbe sembrare troppo grande: dopo tutto, non stiamo limitando le dimensioni da nessuna parte. Ovviamente, avremmo potuto ridimensionare l'immagine con alcune regole CSS, ma è molto meglio generare una miniatura dopo che il file è stato caricato. Questo, tuttavia, richiede alcuni passaggi aggiuntivi.
Per ritagliare e ridimensionare le immagini, abbiamo bisogno di uno strumento separato. Out of the box Carrierwave supporta le gemme RMagick e MiniMagick che, a loro volta, vengono utilizzate per manipolare le immagini con l'aiuto di ImageMagick. ImageMagick è una soluzione open-source che consente di modificare le immagini esistenti e generarne di nuove, quindi prima di procedere è necessario scaricarlo e installarlo. Successivamente, sei libero di scegliere una delle due gemme. Continuerò con MiniMagick, perché è molto più facile da installare e ha un supporto migliore:
gem 'mini_magick'
Correre:
installazione bundle
Quindi includi MiniMagick nel tuo uploader:
includere CarrierWave :: MiniMagick
Ora abbiamo semplicemente bisogno di introdurre una nuova versione per il nostro uploader. Il concetto di versioni (o stili) è usato in molte librerie di upload di file; significa semplicemente che verranno creati file aggiuntivi basati sull'allegato originale con, ad esempio, dimensioni o formati diversi. Presentare una nuova versione chiamata pollice
:
versione: thumb process process resize_to_fill: [350, 350] end
Puoi avere tutte le versioni che vuoi e, per di più, le versioni possono anche essere costruite sopra altre:
versione: small_thumb, from_version:: thumb do process resize_to_fill: [20, 20] end
Se hai già caricato alcune immagini, non avranno miniature disponibili. Questo non è un problema, però, dato che puoi ricrearli dalla console di Rails:
rails c Post.find_each | post | post.image.recreate_versions! (: thumb) se post.immagine?
Infine, mostra la miniatura con un link all'immagine originale:
<%= link_to(image_tag(@post.image.thumb.url, alt: 'Image'), @post.image.url, target: '_blank') if @post.image? %>
Avviare il server e osservare il risultato!
Attualmente il nostro caricamento funziona, ma non stiamo affatto convalidando l'input dell'utente, il che, ovviamente, è sbagliato. Finché vogliamo lavorare solo con le immagini, aggiungiamo le estensioni .png, .jpg e .gif:
def extension_whitelist% w (jpg jpeg gif png) fine
È inoltre possibile aggiungere verifiche del tipo di contenuto definendo a content_type_whitelist
metodo:
def content_type_whitelist / image \ // end
In alternativa, è possibile inserire in una lista nera alcuni tipi di file, ad esempio eseguibili, definendo il file content_type_blacklist
metodo.
Oltre a controllare il tipo e l'estensione di un file, applichiamo un valore inferiore a 1 megabyte. Per farlo, avremo bisogno di un ulteriore gem che supporti le convalide dei file per ActiveModel:
gem 'file_validators'
Installalo:
installazione bundle
Ora introdurre le convalide desiderate (nota che aggiungo anche controlli per il titolo
e corpo
attributi):
valida: title, presence: true, length: minimum: 2 validate: body, presence: true validates: image, file_size: less_than: 1.megabytes
La prossima cosa da fare è aggiungere le traduzioni I18n per i messaggi di errore di Carrierwave:
it: errors: messages: carrierwave_processing_error: "Can not resize image." carrierwave_integrity_error: "Not an image." carrierwave_download_error: "Impossibile scaricare l'immagine." extension_whitelist_error: "Non ti è permesso caricare file% extension, tipi permessi:% allowed_types" extension_blacklist_error: "Non ti è permesso caricare% extension file, tipi proibiti:% prohibited_types"
Al momento, non vengono visualizzati errori di convalida da nessuna parte, quindi creiamo un partial condiviso:
<% if object.errors.any? %>Alcuni errori sono stati trovati:
Impiega questo parziale all'interno del modulo:
<%= render 'shared/errors', object: post %>
Ora prova a caricare alcuni file non validi e osserva il risultato. Dovrebbe funzionare, ma se si sceglie un file valido e non si compila il titolo o il corpo, i controlli continueranno a non riuscire e verrà visualizzato un errore. Tuttavia, il campo file verrà cancellato e l'utente dovrà scegliere di nuovo l'immagine, il che non è molto conveniente. Per risolvere il problema, è necessario aggiungere un altro campo al modulo.
I file persistenti attraverso il ridisplay dei moduli sono in realtà abbastanza semplici. Tutto quello che devi fare è aggiungere un nuovo campo nascosto e permetterlo all'interno del controller:
<%= f.label :image %> <%= f.file_field :image %>
<%= f.hidden_field :image_cache %>
params.require (: post) .permit (: title,: body,: image,: image_cache)
Ora il image_cache
verrà popolato automaticamente e l'immagine non andrà persa. Potrebbe essere utile visualizzare anche una miniatura in modo che l'utente comprenda che l'immagine è stata elaborata correttamente:
<% if post.image? %> <%= image_tag post.image.thumb.url %> <% end %>
Un'altra caratteristica molto comune è la possibilità di rimuovere i file allegati quando si modifica un record. Con Carrierwave, l'implementazione di questa funzione non è un problema. Aggiungi una nuova casella di controllo al modulo:
<% if post.image? %> <%= image_tag post.image.thumb.url %><%= label_tag :remove_image do %> Rimuovi immagine <%= f.check_box :remove_image %> <% end %><% end %>
E consentire il remove_image
attributo:
params.require (: post) .permit (: title,: body,: image,: remove_image,: image_cache)
Questo è tutto! Per rimuovere un'immagine manualmente, utilizzare il remove_image!
metodo:
@ post.remove_image!
Carrierwave fornisce anche una funzionalità molto interessante, la possibilità di caricare file da posizioni remote tramite il loro URL. Introduciamo questa abilità ora aggiungendo un nuovo campo e autorizzando l'attributo corrispondente:
<%= f.text_field :remote_image_url %> Inserisci l'URL per un'immagine
params.require (: post) .permit (: title,: body,: image,: remove_image,: image_cache,: remote_image_url)
Quant'è fico? Non è necessario apportare alcuna modifica e puoi testare subito questa funzionalità!
Supponiamo di volere che il nostro post abbia più allegati disponibili. Con l'attuale configurazione non è possibile, ma per fortuna, Carrierwave supporta anche questo scenario. Per implementare questa funzione, è necessario aggiungere un campo serializzato (per SQLite) o un campo JSON (per Postgres o MySQL). Preferisco la seconda opzione, quindi passiamo a un nuovo adattatore per database ora. Rimuovere la gemma sqlite3 dal Gemfile e aggiungi invece pg:
gemma 'pg'
Installalo:
installazione bundle
Modifica la configurazione del database in questo modo:
default: & default adapter: postgresql pool: 5 timeout: 5000 development: <<: *default database: upload_carrier_dev username: 'YOUR_USER' password: 'YOUR_PASSWORD' host: localhost
Creare il database Postgres corrispondente, quindi generare e applicare la migrazione:
rails g migrazione add_attachments_to_posts allegati: json rails db: migrate
Se preferisci attenersi a SQLite, segui le istruzioni elencate nella documentazione di Carrierwave.
Ora monta gli uploader (nota il plurale!):
mount_uploaders: allegati, ImageUploader
Sto utilizzando lo stesso uploader per gli allegati, ma ovviamente puoi crearne uno nuovo con una configurazione diversa.
Aggiungi il campo di più file al modulo:
<%= f.label :attachments %> <%= f.file_field :attachments, multiple: true %>
Finché il allegati
campo sta per contenere un array, dovrebbe essere permesso nel seguente modo:
params.require (: post) .permit (: title,: body,: image,: remove_image,: image_cache,: remote_image_url, allegati: [])
Infine, puoi scorrere gli allegati del post e visualizzarli come al solito:
<% if @post.attachments? %>
Nota che ogni allegato avrà una miniatura come configurato nel nostro ImageUploader
. Bello!
Rimanere con la memorizzazione dei file non è sempre conveniente e / o possibile dato che, ad esempio, su Heroku non è possibile archiviare file personalizzati. Quindi potresti chiedere come sposare Carrierwave con lo storage cloud Amazon S3? Bene, questo è un compito abbastanza facile. Carrierwave dipende dalla gemma fog-aws per implementare questa funzione:
gemma "nebbia-aws"
Installalo:
installazione bundle
Creiamo un inizializzatore per Carrierwave e configuriamo lo storage cloud globalmente:
CarrierWave.configure do | config | config.fog_provider = 'nebbia / aws' config.fog_credentials = provider: 'AWS', aws_access_key_id: ENV ['S3_KEY'], aws_secret_access_key: ENV ['S3_SECRET'], regione: ENV ['S3_REGION'], config. fog_directory = ENV ['S3_BUCKET'] fine
Ci sono alcune altre opzioni disponibili, che possono essere trovate nella documentazione.
Sto usando la gemma dotenv-rails per impostare le variabili d'ambiente in modo sicuro, ma puoi scegliere qualsiasi altra opzione. Tuttavia, assicurati che la tua coppia di chiavi S3 non sia disponibile pubblicamente, altrimenti chiunque può caricare qualsiasi cosa nel tuo bucket!
Quindi, sostituire il archiviazione: file
coincide:
stoccaggio: nebbia
Oltre a S3, Carrierwave supporta i caricamenti su Google Storage e Rackspace. Questi servizi sono facili da configurare.
Questo è per oggi! Abbiamo coperto tutte le principali funzionalità di Carrierwave e ora puoi iniziare a utilizzarlo nei tuoi progetti. Ha alcune opzioni aggiuntive disponibili, quindi consulta la documentazione.
Se sei bloccato, non esitate a postare le vostre domande. Inoltre, potrebbe essere utile dare uno sguardo al wiki di Carrierwave, che ospita utili articoli "come" che rispondono a molte domande comuni.
Quindi ti ringrazio per essere stato con me e felice codifica!