Mit Rails und Carrierwave hochladen

Dies ist ein weiterer Artikel aus der Reihe "Uploading with Rails". Heute treffen wir uns mit Carrierwave, einer der beliebtesten Lösungen für das Hochladen von Dateien für Rails. Ich mag Carrierwave, weil es einfach ist, anzufangen, es bietet viele Funktionen und ist mit Dutzenden von Anleitungen ausgestattet, die von den Mitgliedern der Community geschrieben werden, damit Sie nicht verloren gehen.

In diesem Artikel erfahren Sie, wie Sie:

  • Integrieren Sie Carrierwave in Ihre Rails-App
  • Validierungen hinzufügen
  • Dateien in Anfragen bestehen
  • Dateien entfernen
  • Thumbnails erstellen
  • Laden Sie Dateien von entfernten Standorten hoch
  • Mehrere Datei-Uploads einführen
  • Unterstützung für Cloud-Speicher hinzufügen

Der Quellcode für diesen Artikel ist auf GitHub verfügbar. Viel Spaß beim Lesen!

Die Grundlagen legen

Erstellen Sie wie immer eine neue Rails-Anwendung:

Schienen neu UploadingWithCarrierwave -T

Für diese Demo verwende ich Rails 5.0.2. Bitte beachten Sie, dass Carrierwave 1 nur Rails 4+ und Ruby 2 unterstützt. Wenn Sie noch auf Rails 3 fahren, schließen Sie die Carrierwave-Version 0.11 an.

Um Carrierwave in Aktion zu sehen, erstellen wir eine sehr einfache Blogging-Anwendung mit einer Sohle Post Modell. Es wird die folgenden Hauptattribute haben:

  • Titel (Schnur)
  • Karosserie (Text)
  • Bild (Schnur) -dieses Feld enthält ein Bild (genauer gesagt der Dateiname), das an den Beitrag angehängt wird

Generieren und wenden Sie eine neue Migration an:

Schienen g Modell Beitragstitel: String Body: Textbild: String Schienen db: migrieren

Einige Routen einrichten:

config / routes.rb

Quellen: Beiträge root: 'posts # index'

Erstellen Sie außerdem einen sehr einfachen Controller:

posts_controller.rb

Klasse 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

Lass uns jetzt das machen Index Aussicht:

views / posts / index.html.erb

Beiträge

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

Und der entsprechende Teil:

Ansichten / Beiträge / _post.html.erb

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

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

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


Hier benutze ich die Rails kürzen Methode, um nur die ersten 150 Symbole des Beitrags anzuzeigen. Bevor wir andere Ansichten und Formulare erstellen, integrieren wir zunächst Carrierwave in die Anwendung.

Carrierwave integrieren

Legen Sie einen neuen Edelstein in die Gemfile:

Gemfile

gem 'carrierwave', '~> 1.0'

Lauf:

Bundle installieren

Carrierwave speichert seine Konfiguration darin Uploader die in Ihren Modellen enthalten sind. Verwenden Sie zum Generieren eines Uploaders den folgenden Befehl:

Schienen erzeugen Uploader Image

Nun drinnen App / Uploader, Sie finden eine neue Datei namens image_uploader.rb. Beachten Sie, dass es einige nützliche Kommentare und Beispiele enthält, so dass Sie damit beginnen können. In dieser Demo werden wir ActiveRecord verwenden, aber Carrierwave unterstützt auch Mongoid, Sequel und DataMapper.

Als nächstes müssen wir oder einschließen montieren diesen Uploader in das Modell:

Modelle / post.rb

mount_uploader: Bild, ImageUploader

Der Uploader hat bereits normale Standardeinstellungen, aber zumindest müssen wir auswählen, wo die hochgeladenen Dateien gespeichert werden. Jetzt setzen wir den Dateispeicher ein:

uploaders / image_uploader.rb

Speicher: Datei

Standardmäßig werden Dateien in der öffentlich / Uploads Verzeichnis, so dass es am besten aus dem Versionskontrollsystem ausgeschlossen wird:

.Gitignore

öffentlich / Uploads

Sie können auch das ändern store_dir Methode in Ihrem Uploader, um einen anderen Speicherort auszuwählen.

An dieser Stelle können wir eine neue Ansicht und ein Formular erstellen, um Dateien hochzuladen:

views / posts / new.html.erb

Beitrag hinzufügen

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

Ansichten / Beiträge / _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 %>

Notiere dass der PostsController muss nicht geändert werden, da wir das bereits erlaubt haben Bild Attribut.

Zuletzt erstellen Sie die Bearbeitungsansicht:

views / posts / edit.html.erb

Beitrag bearbeiten

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

Das ist es! Sie können den Server starten und versuchen, einen Beitrag mit einem Image zu erstellen. Das Problem ist, dass dieses Bild nirgendwo sichtbar ist. Fahren wir mit dem nächsten Abschnitt fort und fügen Sie eine Show-Seite hinzu!

Bilder anzeigen

Die einzige Ansicht, die wir noch nicht erstellt haben, ist also Show. Jetzt hinzufügen:

views / posts / 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) %>

Wie Sie sehen, ist das Anzeigen eines Anhangs sehr einfach: Sie müssen nur sagen @ post.image.url um die URL eines Bildes zu packen. Um einen Pfad zu der Datei zu erhalten, verwenden Sie die current_path Methode. Beachten Sie, dass Carrierwave auch eine Bild? Methode, um zu prüfen, ob überhaupt ein Anhang vorhanden ist (der Bild Methode selbst wird nie zurückkehren Null, auch wenn die Datei nicht vorhanden ist).

Nachdem Sie zu einem Beitrag navigiert haben, sollten Sie ein Bild sehen, das jedoch möglicherweise zu groß erscheint: Schließlich beschränken wir die Bemaßung nirgendwo. Natürlich hätten wir das Bild mit ein paar CSS-Regeln verkleinern können, aber es ist viel besser, ein Miniaturbild zu erstellen, nachdem die Datei hochgeladen wurde. Dies erfordert jedoch einige zusätzliche Schritte.

Thumbnails erstellen

Um Bilder zuzuschneiden und zu skalieren, benötigen wir ein separates Werkzeug. Im Auslieferungszustand bietet Carrierwave RMagick- und MiniMagick-Edelsteine ​​an, die wiederum zur Bildbearbeitung mit Hilfe von ImageMagick verwendet werden. ImageMagick ist eine Open-Source-Lösung, mit der Sie vorhandene Bilder bearbeiten und neue erstellen können. Bevor Sie fortfahren, müssen Sie sie herunterladen und installieren. Als nächstes können Sie die beiden Edelsteine ​​auswählen. Ich bleibe bei MiniMagick, weil es viel einfacher zu installieren ist und bessere Unterstützung bietet: 

Gemfile

gem 'mini_magick'

Lauf:

Bundle installieren

Dann fügen Sie MiniMagick in Ihren Uploader ein:

uploaders / image_uploader.rb

umfassen CarrierWave :: MiniMagick

Jetzt müssen wir einfach eine neue Version in unseren Uploader einführen. Das Konzept von Versionen (oder Stile) wird in vielen Bibliotheken zum Hochladen von Dateien verwendet. es bedeutet einfach, dass zusätzliche Dateien, die auf dem ursprünglichen Anhang basieren, beispielsweise mit anderen Abmessungen oder Formaten erstellt werden. Führen Sie eine neue Version ein Daumen:

uploaders / image_uploader.rb

version: thumb do process resize_to_fill: [350, 350] end

Sie können so viele Versionen haben, wie Sie möchten. Darüber hinaus können Versionen sogar auf anderen basieren:

uploaders / image_uploader.rb

version: small_thumb, from_version:: thumb do size resize_to_fill: [20, 20] end

Wenn Sie bereits einige Bilder hochgeladen haben, stehen ihnen keine Miniaturbilder zur Verfügung. Dies ist jedoch kein Problem, da Sie sie von der Rails-Konsole aus neu erstellen können:

Schienen c Post.find_each | post | post.image.recreate_versions! (: thumb) if post.image?

Zuletzt zeigen Sie Ihre Miniaturansicht mit einem Link zum Originalbild an:

views / posts / show.html.erb

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

Starten Sie den Server und beobachten Sie das Ergebnis!

Validierungen hinzufügen

Momentan funktioniert unser Upload, aber wir validieren keine Benutzereingaben, was natürlich schlecht ist. Wenn wir nur mit Bildern arbeiten möchten, lassen Sie uns die Erweiterungen .png, .jpg und .gif auf die Whitelist setzen:

uploaders / image_uploader.rb

def extension_whitelist% w (jpg jpeg gif png) end

Sie können auch Inhaltstypüberprüfungen hinzufügen, indem Sie a definieren content_type_whitelist Methode:

uploaders / image_uploader.rb

def content_type_whitelist / image \ // end

Alternativ ist es möglich, einige Dateitypen, z. B. ausführbare Dateien, durch Definieren der Dateierweiterung auf die schwarze Liste zu setzen content_type_blacklist Methode.

Abgesehen von der Überprüfung von Dateityp und -erweiterung, lassen Sie uns festlegen, dass diese weniger als 1 Megabyte beträgt. Dafür benötigen wir ein zusätzliches Juwel, das Dateivalidierungen für ActiveModel unterstützt:

Gemfile

gem 'file_validators'

Es installieren:

Bundle installieren

Führen Sie nun die gewünschten Validierungen ein (beachten Sie, dass ich auch Checks für das Titel und Karosserie Attribute):

Modelle / post.rb

validiert: Titel, Präsenz: wahr, Länge: Minimum: 2 validiert: Körper, Präsenz: wahr validiert: Bild, Dateigröße: less_than: 1.Megabytes

Als nächstes müssen Sie I18n-Übersetzungen für die Fehlermeldungen von Carrierwave hinzufügen:

config / locales / de.yml

de: errors: messages: carrierwave_processing_error: "Bildgröße kann nicht geändert werden." carrierwave_integrity_error: "Kein Bild." carrierwave_download_error: "Bild konnte nicht heruntergeladen werden." extension_whitelist_error: "Sie dürfen% extension -Dateien nicht hochladen, zulässige Typen:% Allowed_types" extension_blacklist_error: "Sie dürfen keine% extension -Dateien hochladen, verbotene Typen:% verboten_types"

Derzeit zeigen wir keine Validierungsfehler an, also erstellen wir ein gemeinsames Partial:

views / shared / _errors.html.erb

<% if object.errors.any? %> 

Einige Fehler wurden gefunden:

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

Verwenden Sie diesen Teil innerhalb des Formulars:

Ansichten / Beiträge / _form.html.erb

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

Versuchen Sie nun einige ungültige Dateien hochzuladen und beobachten Sie das Ergebnis. Es sollte funktionieren, aber wenn Sie eine gültige Datei auswählen und den Titel oder Text nicht ausfüllen, schlagen die Prüfungen immer noch fehl und es wird ein Fehler angezeigt. Das Dateifeld wird jedoch gelöscht, und der Benutzer muss das Bild erneut auswählen, was nicht sehr praktisch ist. Um dies zu beheben, müssen wir dem Formular ein weiteres Feld hinzufügen.

Bestehende Dateien in Anfragen bestehen

Das Bestehen von Dateien in Formulardarstellungen ist eigentlich ganz einfach. Alles was Sie tun müssen, ist ein neues verstecktes Feld hinzuzufügen und es im Controller zuzulassen:

views / shared / _form.html.erb

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

posts_controller.rb

params.require (: post) .permit (: title,: body,: image,: image_cache)

Jetzt die image_cache wird automatisch ausgefüllt und das Bild geht nicht verloren. Es kann hilfreich sein, auch eine Miniaturansicht anzuzeigen, damit der Benutzer versteht, dass das Bild erfolgreich verarbeitet wurde: 

views / shared / _form.html.erb

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

Bilder entfernen

Eine weitere sehr häufige Funktion ist die Möglichkeit, angehängte Dateien beim Bearbeiten eines Datensatzes zu entfernen. Die Implementierung dieser Funktion ist mit Carrierwave kein Problem. Fügen Sie dem Formular ein neues Kontrollkästchen hinzu:

views / shared / _form.html.erb

<% if post.image? %> <%= image_tag post.image.thumb.url %> 
<%= label_tag :remove_image do %> Entferne Bild <%= f.check_box :remove_image %> <% end %>
<% end %>

Und erlaube das entferne Bild Attribut:

posts_controller.rb

params.require (: post) .permit (: title,: body,: image,: remove_image,: image_cache)

Das ist es! Um ein Bild manuell zu entfernen, verwenden Sie die entferne Bild! Methode:

@ post.remove_image!

Hochladen von einem entfernten Standort

Carrierwave bietet auch eine sehr coole Funktion: die Möglichkeit, Dateien von entfernten Standorten nach ihrer URL hochzuladen. Lassen Sie uns diese Fähigkeit jetzt einführen, indem Sie ein neues Feld hinzufügen und das entsprechende Attribut zulassen: 

views / shared / _form.html.erb

<%= f.text_field :remote_image_url %> Geben Sie die URL zu einem Bild ein

posts_controller.rb

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

Wie cool ist das? Sie müssen keine Änderungen vornehmen und Sie können diese Funktion sofort testen!

Mit mehreren Uploads arbeiten

Angenommen, wir möchten, dass unser Posting mehrere Anhänge enthält. Mit dem aktuellen Setup ist dies nicht möglich, aber zum Glück unterstützt Carrierwave ein solches Szenario. Um diese Funktion zu implementieren, müssen Sie entweder ein serialisiertes Feld (für SQLite) oder ein JSON-Feld (für Postgres oder MySQL) hinzufügen. Ich bevorzuge die letztere Option, also wechseln wir jetzt zu einem neuen Datenbankadapter. Entfernen Sie den sqlite3-Edelstein aus dem Gemfile und pg stattdessen hinzufügen:

Gemfile

Juwel 'pg'

Es installieren:

Bundle installieren

Ändern Sie die Datenbankkonfiguration folgendermaßen:

config / database.yml

default: & default adapter: postgresql pool: 5 timeout: 5000 entwicklung: <<: *default database: upload_carrier_dev username: 'YOUR_USER' password: 'YOUR_PASSWORD' host: localhost

Erstellen Sie die entsprechende Postgres-Datenbank und generieren Sie die Migration, und wenden Sie sie an:

Schienen g Migration add_attachments_to_posts Anhänge: Json Schienen db: migrieren

Wenn Sie es vorziehen, bei SQLite zu bleiben, befolgen Sie die Anweisungen in der Carrierwave-Dokumentation.

Mounten Sie jetzt die Uploader (beachten Sie die Pluralform!):

Modell / post.rb

mount_uploaders: Anhänge, ImageUploader

Ich verwende denselben Uploader für Anhänge, aber Sie können natürlich einen neuen mit einer anderen Konfiguration generieren.

Fügen Sie das Feld mit mehreren Dateien zu Ihrem Formular hinzu:

views / shared / _form.html.erb

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

Solange die Anlagen Feld wird ein Array enthalten, es sollte auf folgende Weise erlaubt sein:

posts_controller.rb

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

Zuletzt können Sie die Anhänge des Beitrags durchlaufen und wie gewohnt anzeigen:

views / shared / 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 %>

Beachten Sie, dass jeder Anhang eine Miniaturansicht haben wird, die in unserem Ordner konfiguriert ist ImageUploader. nett!

Cloud Storage verwenden

Das Speichern von Dateien ist nicht immer bequem und / oder möglich, da beispielsweise auf Heroku keine benutzerdefinierten Dateien gespeichert werden können. Daher könnten Sie sich fragen, wie Sie Carrierwave mit einem Amazon S3-Cloudspeicher verbinden können. Nun, das ist auch eine ziemlich einfache Aufgabe. Carrierwave ist für die Implementierung dieser Funktion auf den Nebel-Aw-Edelstein angewiesen:

Gemfile

gem "fog-aws"

Es installieren:

Bundle installieren

Lassen Sie uns einen Initialisierer für Carrierwave erstellen und den Cloud-Speicher global konfigurieren:

config / initializers / carrierwave.rb

CarrierWave.config do | config | config.fog_provider = 'fog / aws' config.fog_credentials = provider: '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'] end

Es gibt einige andere Optionen, die Sie in der Dokumentation finden.

Ich benutze den dotenv-schienen-Edelstein, um die Umgebungsvariablen auf sichere Weise festzulegen, aber Sie können jede andere Option wählen. Stellen Sie jedoch sicher, dass Ihr S3-Schlüsselpaar nicht öffentlich verfügbar ist. Andernfalls kann jeder etwas in Ihren Bucket hochladen!

Als nächstes ersetzen Sie die Speicher: Datei Zeile mit:

uploaders / image_uploader.rb

Lagerung: Nebel

Neben S3 unterstützt Carrierwave auch Uploads zu Google Storage und Rackspace. Diese Dienste sind ebenfalls einfach einzurichten.

Fazit

Das ist es für heute! Wir haben alle wichtigen Funktionen von Carrierwave behandelt und können sie jetzt in Ihren Projekten einsetzen. Es stehen einige zusätzliche Optionen zur Verfügung, also durchsuchen Sie die Dokumentation.

Wenn Sie nicht weiterkommen, zögern Sie nicht, Ihre Fragen zu posten. Es kann auch nützlich sein, einen Blick in das Wiki von Carrierwave zu werfen, in dem nützliche Artikel zum "Wie" gehostet werden, die viele häufig gestellte Fragen beantworten.

Ich danke Ihnen, dass Sie bei mir geblieben sind, und fröhliche Kodierung!