Det här är en annan artikel i serien "Uploading with Rails". Idag kommer vi att träffa Carrierwave-en av de mest populära filuppladdningslösningarna för Rails. Jag gillar Carrierwave eftersom det är lätt att komma igång, det har många funktioner ur lådan, och det ger dussintals "hur" artiklar som skrivs av medlemmarna i samhället, så du kommer inte gå vilse.
I den här artikeln lär du dig att:
Källkoden för den här artikeln finns på GitHub. Njut av att läsa!
Börja med att skapa en ny Rails-applikation som alltid:
spårar nya UploadingWithCarrierwave -T
För den här demo använder jag Rails 5.0.2. Observera att Carrierwave 1 endast stöder Rails 4+ och Ruby 2. Om du fortfarande kör på Rails 3, kopplar du sedan upp Carrierwave version 0.11.
För att se Carrierwave i åtgärd kommer vi att skapa en mycket enkel bloggapplikation med en sål Posta
modell. Den kommer att ha följande huvudattribut:
titel
(sträng
)kropp
(text
)bild
(sträng
) -Detta fält kommer att innehålla en bild (en fils namn, för att vara exakt) bifogad postenGenerera och tillämpa en ny migrering:
rails g model Posttitel: strängkropp: textbild: strängskenor db: migrera
Ställ in några vägar:
resurser: inlägg root till: 'inlägg # index'
Skapa också en mycket grundläggande kontroller:
klass 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
Nu låt oss hantla index se:
inlägg
<%= link_to 'Add post', new_post_path %> <%= render @posts %>
Och motsvarande del:
<%= link_to post.title, post_path(post) %>
<%= truncate(post.body, length: 150) %>
<%= link_to 'Edit', edit_post_path(post) %>
Här använder jag Rails stympa
Metod för att bara visa de första 150 symbolerna från posten. Innan vi skapar andra visningar och ett formulär delvis, låt oss först integrera Carrierwave i programmet.
Släpp in en ny pärla i Gemfile:
pärla "carrierwave", "~> 1.0"
Springa:
buntinstallation
Carrierwave lagrar sin konfiguration inuti uppladdare som ingår i dina modeller. För att skapa en uppladdare, använd följande kommando:
rails generera uploader Image
Nu inuti app / uppladdare, Du hittar en ny fil som heter image_uploader.rb. Observera att det har några användbara kommentarer och exempel, så du kan använda den för att komma igång. I denna demo kommer vi att använda ActiveRecord, men Carrierwave har också stöd för Mongoid, Sequel och DataMapper.
Därefter måste vi inkludera eller montera den här uppladdaren i modellen:
mount_uploader: bild, ImageUploader
Uppladdaren har redan sanna standardinställningar, men åtminstone måste vi välja var de uppladdade filerna ska lagras. För närvarande, låt oss anställa fillagring:
lagring: fil
Som standard kommer filer att placeras inuti offentliga / uppladdningar katalog, så det är bäst att utesluta det från versionskontrollsystemet:
offentliga / uppladdningar
Du kan också ändra store_dir
metod inom din uppladdare för att välja någon annan plats.
Vid denna tidpunkt kan vi skapa en ny vy och ett formulär delvis för att börja ladda upp filer:
Lägg till inlägg
<%= 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 %>
Observera att PostsController
behöver inte ändras som vi redan har tillåtit bild
attribut.
Slutligen skapa redigeringsvyn:
Redigera inlägg
<%= render 'form', post: @post %>
Det är allt! Du kan starta servern och försöka skapa ett inlägg med en bild. Problemet är att bilden inte är synlig någonstans, så låt oss fortsätta till nästa avsnitt och lägga till en visningssida!
Så den enda vy som vi inte har skapat ännu är show. Lägg till det nu:
<%= 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) %>
Som du kan se är det väldigt lätt att visa en bilaga: allt du behöver göra är att säga @ post.image.url
att ta tag i en bilds URL. För att få en sökväg till filen, använd current_path
metod. Observera att Carrierwave också ger en bild?
metod för oss att kontrollera om det finns en bilaga alls (den bild
Metoden själv kommer aldrig att återvända noll
, även om filen inte är närvarande).
Nu, efter att du navigerat till ett inlägg, bör du se en bild, men det kan verka för stor: trots allt begränsar vi inte dimensionerna någonstans. Självklart kan vi ha minskat bilden med några CSS-regler, men det är mycket bättre att skapa en miniatyrbild efter att filen har laddats upp. Detta kräver dock några ytterligare steg.
För att beskära och skala bilder behöver vi ett separat verktyg. Utanför lådan har Carrierwave stöd för RMagick och MiniMagick ädelstenar som i sin tur används för att manipulera bilder med hjälp av ImageMagick. ImageMagick är en öppen källkodslösning som gör att du kan redigera befintliga bilder och skapa nya, så innan du fortsätter måste du hämta och installera det. Därefter är du fri att välja någon av de två pärlorna. Jag håller med MiniMagick, eftersom det är mycket lättare att installera och det har bättre stöd:
pärla "mini_magick"
Springa:
buntinstallation
Lägg sedan till MiniMagick i din uppladdare:
Inkludera CarrierWave :: MiniMagick
Nu behöver vi helt enkelt introducera en ny version till vår uppladdare. Konceptet av versioner (eller stilar) används i många filuppladdningsbibliotek; det betyder helt enkelt att ytterligare filer baserat på den ursprungliga bilagan kommer att skapas med till exempel olika dimensioner eller format. Presentera en ny version som heter tumme
:
version: tummen gör processen resize_to_fill: [350, 350] slutet
Du kan ha så många versioner som du vill, och dessutom kan versioner även byggas utöver andra:
version: small_thumb, from_version:: tummen gör processen resize_to_fill: [20, 20] slutet
Om du redan har laddat upp några bilder kommer de inte att ha miniatyrer tillgängliga. Detta är inte ett problem, eftersom du kan skapa dem igen från spårningskonsolen:
rails c Post.find_each | post | post.image.recreate_versions! (: thumb) om post.image?
Slutligen, visa din miniatyrbild med en länk till originalbilden:
<%= link_to(image_tag(@post.image.thumb.url, alt: 'Image'), @post.image.url, target: '_blank') if @post.image? %>
Starta servern och följ resultatet!
För närvarande fungerar vår uppladdning, men vi godkänner inte alls användarinmatning, vilket är självklart dåligt. Så länge vi bara vill arbeta med bilder, låt oss vitlista .png, .jpg och .gif-tillägg:
def extension_whitelist% w (jpg jpeg gif png) slut
Du kan också lägga till innehållstypskontroller genom att definiera en content_type_whitelist
metod:
def content_type_whitelist / image \ // end
Alternativt är det möjligt att svartlista vissa filtyper, till exempel körbara filer, genom att definiera content_type_blacklist
metod.
Bortsett från att du kontrollerar en fils typ och förlängning, låt oss genomdriva det för att vara mindre än 1 megabyte. För att göra det behöver vi en extra pärla som stöder filvalideringar för ActiveModel:
pärla "file_validators"
Installera det:
buntinstallation
Nu introducera önskade valideringar (notera att jag också lägger till kontroller för titel
och kropp
attribut):
validerar: titel, närvaro: sann, längd: minimum: 2 validerar: kropp, närvaro: true validates: image, file_size: less_than: 1.megabytes
Nästa sak att göra är att lägga till I18n-översättningar för Carrierwaves felmeddelanden:
sv: fel: meddelanden: carrierwave_processing_error: "Kan inte ändra storlek på bild." carrierwave_integrity_error: "Inte en bild." carrierwave_download_error: "Kunde inte ladda ner bild." extension_whitelist_error: "Du får inte ladda upp% extension -filer, tillåtna typer:% allowed_types" extension_blacklist_error: "Du får inte ladda upp% extension -filer, förbjudna typer:% prohibited_types"
För närvarande visar vi inte valideringsfel någonstans, så låt oss skapa en delad del:
<% if object.errors.any? %>Några fel hittades:
Anlita detta partiellt inuti formuläret:
<%= render 'shared/errors', object: post %>
Försök nu ladda upp några ogiltiga filer och observera resultatet. Det ska fungera, men om du väljer en giltig fil och inte fyller i titeln eller kroppen, kommer kontrollerna fortfarande att misslyckas och ett fel kommer att visas. Filfältet kommer emellertid att rensas ut och användaren måste välja bilden igen, vilket inte är särskilt bekvämt. För att fixa det måste vi lägga till ett annat fält i formuläret.
Det är faktiskt ganska lätt att behålla filer över formredigeringar. Allt du behöver göra är att lägga till ett nytt gömt fält och tillåta det inom kontrollenheten:
<%= f.label :image %> <%= f.file_field :image %>
<%= f.hidden_field :image_cache %>
params.require (: post) .permit (: title,: body,: image,: image_cache)
Nu den image_cache
kommer att fyllas i automatiskt och bilden kommer inte att gå vilse. Det kan vara tillrådligt att visa en miniatyrbild så att användaren förstår att bilden har bearbetats framgångsrikt:
<% if post.image? %> <%= image_tag post.image.thumb.url %> <% end %>
En annan mycket vanlig funktion är möjligheten att ta bort bifogade filer när du redigerar en post. Med Carrierwave är det inte ett problem att implementera denna funktion. Lägg till en ny kryssruta i formuläret:
<% if post.image? %> <%= image_tag post.image.thumb.url %><%= label_tag :remove_image do %> Ta bort bilden <%= f.check_box :remove_image %> <% end %><% end %>
Och tillåta remove_image
attribut:
params.require (: post) .permit (: title,: body,: image,: remove_image,: image_cache)
Det är allt! Om du vill ta bort en bild manuellt använder du remove_image!
metod:
@ post.remove_image!
Carrierwave ger också en mycket cool funktion ur lådan: möjligheten att ladda upp filer från avlägsna platser via deras webbadress. Låt oss introducera denna förmåga nu genom att lägga till ett nytt fält och tillåta motsvarande attribut:
<%= f.text_field :remote_image_url %> Ange URL till en bild
params.require (: post) .permit (: title,: body,: image,: remove_image,: image_cache,: remote_image_url)
Hur coolt är inte det? Du behöver inte göra några förändringar alls, och du kan testa denna funktion direkt!
Antag att vi vill att vårt inlägg ska ha flera bilagor tillgängliga. Med den nuvarande inställningen är det inte möjligt, men lyckligtvis Carrierwave stöder också ett sådant scenario. För att implementera denna funktion måste du lägga till antingen ett seriellt fält (för SQLite) eller ett JSON-fält (för Postgres eller MySQL). Jag föredrar det senare alternativet, så låt oss byta till en ny databasadapter nu. Ta bort sqlite3-pärlan från Gemfile och lägg till pg istället:
pärla 'pg'
Installera det:
buntinstallation
Ändra databaskonfigurationen så här:
standard: & standardadapter: postgresql pool: 5 timeout: 5000 utveckling: <<: *default database: upload_carrier_dev username: 'YOUR_USER' password: 'YOUR_PASSWORD' host: localhost
Skapa motsvarande Postgres-databas, och generera och tillämpa migreringen:
rails g migration add_attachments_to_posts bilagor: json rails db: migrera
Om du föredrar att hålla fast vid SQLite följer du instruktionerna i Carrierwaves dokumentation.
Montera nu uppladdningsenheterna (notera pluralformen!):
mount_uploaders: bilagor, ImageUploader
Jag använder samma uppladdare för bilagor, men självklart kan du skapa en ny med en annan konfiguration.
Lägg till flervalsfältet i ditt formulär:
<%= f.label :attachments %> <%= f.file_field :attachments, multiple: true %>
Så länge som bilagor
fältet kommer att innehålla en matris, bör det tillåtas på följande sätt:
params.require (: post) .permit (: title,: body,: bild,: remove_image,: image_cache,: remote_image_url, bilagor: [])
Slutligen kan du iterera över inläggets bilagor och visa dem som vanligt:
<% if @post.attachments? %>
Observera att varje bilaga kommer att ha en miniatyrbild som konfigurerad i vår ImageUploader
. Trevlig!
Stickning med fillagring är inte alltid bekvämt och / eller möjligt, till exempel på Heroku är det inte möjligt att lagra anpassade filer. Därför kan du fråga hur man gifter sig med Carrierwave med Amazon S3-molnlagring? Tja, det är också en ganska lätt uppgift. Carrierwave beror på dimma-aws-pärlan för att genomföra denna funktion:
pärla "dimma-aws"
Installera det:
buntinstallation
Låt oss skapa en initializer för Carrierwave och konfigurera molnlagret globalt:
CarrierWave.configure do | config | config.fog_provider = 'dimma / aws' config.fog_credentials = leverantör: 'AWS', aws_access_key_id: ENV ['S3_KEY'], aws_secret_access_key: ENV ['S3_SECRET'], region: ENV ['S3_REGION'], config. fog_directory = ENV ['S3_BUCKET'] slutet
Det finns några andra alternativ, som finns i dokumentationen.
Jag använder dotenv-skenerns pärla för att ställa miljövariablerna på ett säkert sätt, men du kan välja något annat alternativ. Se dock till att ditt S3-nyckelpar inte är tillgängligt offentligt, för annars kan någon ladda upp något till din hink!
Nästa, ersätt lagring: fil
linje med:
lagring: dimma
Bortsett från S3, stödjer Carrierwave uppladdningar till Google Storage and Rackspace. Dessa tjänster är lätta att installera också.
Detta är det för idag! Vi har täckt alla viktiga funktioner i Carrierwave, och nu kan du börja använda det i dina projekt. Det har några ytterligare alternativ tillgängliga, så bläddra i dokumentationen.
Om du är fast, tveka inte att skicka dina frågor. Det kan också vara bra att ta en titt på Carrierwaves wiki, som är värd för användbara "hur man" artiklar som svarar på många vanliga frågor.
Så jag tackar dig för att du bodde med mig och glad kodning!