Es gibt viele Dateien zum Hochladen von Edelsteinen wie CarrierWave, Paperclip und Dragonfly, um nur einige zu nennen. Sie alle haben ihre Besonderheiten, und wahrscheinlich haben Sie bereits mindestens einen dieser Edelsteine verwendet.
Heute möchte ich jedoch eine relativ neue, aber sehr coole Lösung namens Shrine vorstellen, die von Janko Marohnić erstellt wurde. Im Gegensatz zu einigen anderen ähnlichen Edelsteinen wird ein modularer Ansatz verfolgt, was bedeutet, dass jedes Feature als Modul (oder Plugin in der Terminologie von Shrine). Möchten Sie Validierungen unterstützen? Fügen Sie ein Plugin hinzu. Möchten Sie einige Dateien bearbeiten? Fügen Sie ein Plugin hinzu! Ich liebe diesen Ansatz sehr, da er auf einfache Weise kontrolliert, welche Funktionen für welches Modell verfügbar sind.
In diesem Artikel zeige ich Ihnen, wie Sie:
Der Quellcode für diesen Artikel ist auf GitHub verfügbar.
Die Arbeitsdemo finden Sie hier.
Erstellen Sie zunächst eine neue Rails-Anwendung ohne die Standard-Testsuite:
Schienen neuer FileGuru -T
Ich werde Rails 5 für diese Demo verwenden, aber die meisten Konzepte gelten auch für die Versionen 3 und 4.
Lass den Schrein-Edelstein in dein Gemfile fallen:
Juwel "Schrein"
Dann renne:
Bundle installieren
Jetzt benötigen wir ein Modell, das ich anrufen werde Foto
. Shrine speichert alle dateibezogenen Informationen in einer speziellen Textspalte, die mit a endet _Daten
Suffix. Erstellen Sie die entsprechende Migration und wenden Sie sie an:
Schienen g Modell Fototitel: string image_data: Text Schienen db: migrieren
Beachten Sie, dass der letzte Befehl für ältere Versionen von Rails lauten sollte:
rake db: migrieren
Konfigurationsoptionen für Shrine können sowohl global als auch pro Modell festgelegt werden. Die globalen Einstellungen werden natürlich in der Initialisierungsdatei vorgenommen. Dort werde ich die notwendigen Dateien anschließen und Plugins. In Shrine werden Plugins verwendet, um Funktionsbestandteile in separate Module zu extrahieren. So haben Sie die volle Kontrolle über alle verfügbaren Funktionen. Es gibt beispielsweise Plugins für die Validierung, Bildverarbeitung, das Caching von Anhängen und mehr.
Lassen Sie uns zunächst zwei Plugins hinzufügen: eines zur Unterstützung von ActiveRecord und eines zur Einrichtung der Protokollierung. Sie werden global aufgenommen. Richten Sie außerdem den Dateisystemspeicher ein:
erfordern "Schrein" erfordern "Schrein / Speicher / Dateisystem" Shrine.plugin: activerecord Shrine.plugin: Protokollierung, Protokollierung: Rails.logger Shrine.storages = cache: Shrine :: Storage :: FileSystem.new (Präfix "public") : "uploads / cache"), store: Shrine :: Storage :: FileSystem.new ("public", Präfix: "uploads / store"),
Logger gibt einfach einige Debugging-Informationen in der Konsole aus, um anzugeben, wie viel Zeit für die Verarbeitung einer Datei aufgewendet wurde. Das kann nützlich sein.
2015-10-09T20: 06: 06.676Z # 25602: STORE [Cache] ImageUploader [: avatar] Benutzer [29543] 1 Datei (0,1 s) 2015-10-09T20: 06: 06.854Z # 25602: PROCESS [store]: ImageUploader [: avatar] User [29543] 1-3 Dateien (0.22s) 2015-10-09T20: 06: 07.133Z # 25602: DELETE [zerstört]: ImageUploader [: avatar] User [29543] 3 Dateien (0.07s)
Alle hochgeladenen Dateien werden im gespeichert öffentlich / Uploads Verzeichnis. Ich möchte diese Dateien nicht in Git verfolgen, schließen Sie diesen Ordner aus:
öffentlich / Uploads
Erstellen Sie nun eine spezielle "Uploader" -Klasse, in der modellspezifische Einstellungen gehostet werden. Im Moment wird diese Klasse leer sein:
Klasse ImageUploader < Shrine end
Fügen Sie diese Klasse schließlich in die Foto
Modell:
include ImageUploader [: image]
[:Bild]
fügt ein virtuelles Attribut hinzu, das beim Erstellen eines Formulars verwendet wird. Die obige Zeile kann umgeschrieben werden als:
Include ImageUploader.attachment (: image) # oder ImageUploader :: Attachment.new (: image) enthalten
Nett! Jetzt ist das Modell mit Shrines Funktionalität ausgestattet und wir können mit dem nächsten Schritt fortfahren.
Für die Zwecke dieser Demo benötigen wir nur einen Controller zum Verwalten von Fotos. Das Index
Seite wird als Wurzel dienen:
Klasse PhotosController < ApplicationController def index @photos = Photo.all end end
Die Aussicht:
Fotos
<%= link_to 'Add Photo', new_photo_path %> <%= render @photos %>
Um das zu rendern @Fotos
Array ist ein Teil erforderlich:
<% if photo.image_data? %> <%= image_tag photo.image_url %> <% end %><%= photo.title %> | <%= link_to 'Edit', edit_photo_path(photo) %>
Bilddaten?
ist eine von ActiveRecord präsentierte Methode, die prüft, ob ein Datensatz ein Bild enthält.
Bild URL
ist eine Shrine-Methode, die einfach einen Pfad zum Originalbild zurückgibt. Natürlich ist es viel besser, stattdessen ein kleines Miniaturbild anzuzeigen, aber wir werden uns später darum kümmern.
Fügen Sie alle erforderlichen Routen hinzu:
Ressourcen: Nur Fotos: [: Neu,: Erstellen,: Index,: Bearbeiten,: Aktualisieren] Stamm 'Fotos # Index'
Das ist es - die Vorarbeit ist getan, und wir können mit dem interessanten Teil fortfahren!
In diesem Abschnitt zeige ich Ihnen, wie Sie die Funktionalität hinzufügen, um Dateien tatsächlich hochzuladen. Die Controller-Aktionen sind sehr einfach:
def new @photo = Photo.new Ende def create @photo = Photo.new (photo_params) if @ photo.save flash [: success] = 'Foto hinzugefügt! redirect_to photos_path else rendere 'new' end end
Das einzige Problem ist, dass Sie für starke Parameter das zulassen müssen Bild
virtuelles Attribut, nicht das Bilddaten
.
private def photo_params params.require (: photo) .permit (: title,: image) ende
Erstellen Sie die Neu
Aussicht:
Foto hinzufügen
<%= render 'form' %>
Das Teilformular des Formulars ist auch trivial:
<%= form_for @photo do |f| %> <%= render "shared/errors", object: @photo %> <%= f.label :title %> <%= f.text_field :title %> <%= f.label :image %> <%= f.file_field :image %> <%= f.submit %> <% end %>
Beachten Sie erneut, dass wir das verwenden Bild
Attribut, nicht das Bilddaten
.
Fügen Sie schließlich einen weiteren Teil der Anzeigefehler hinzu:
<% if object.errors.any? %>Die folgenden Fehler wurden gefunden:
Das ist so ziemlich alles - Sie können jetzt Bilder hochladen.
Natürlich muss noch viel mehr getan werden, um die Demo-App abzuschließen. Das Hauptproblem ist, dass die Benutzer absolut jeden Dateityp mit beliebiger Größe hochladen können, was nicht besonders groß ist. Fügen Sie daher ein weiteres Plugin hinzu, um Validierungen zu unterstützen:
Shrine.plugin: validation_helpers
Richten Sie die Validierungslogik für die ein ImageUploader
:
Attacher.validate do validate_max_size 1.megabyte, Nachricht: "ist zu groß (max. 1 MB)." Validate_mime_type_inclusion ['image / jpg', 'image / jpeg', 'image / png'] end
Ich darf nur JPG- und PNG-Bilder mit einer Größe von weniger als 1 MB hochladen. Passen Sie diese Regeln an, wenn Sie es für richtig halten.
Beachten Sie außerdem, dass Shrine standardmäßig den MIME-Typ einer Datei mithilfe des Content-Type-HTTP-Headers ermittelt. Dieser Header wird vom Browser übergeben und wird nur basierend auf der Dateierweiterung festgelegt. Dies ist nicht immer wünschenswert.
Wenn Sie den MIME-Typ basierend auf dem Inhalt der Datei ermitteln möchten, verwenden Sie ein Plugin mit dem Namen determin_mime_type. Ich werde es in die Uploader-Klasse aufnehmen, da andere Modelle diese Funktionalität möglicherweise nicht benötigen:
Plugin: determin_mime_type
Dieses Plugin verwendet standardmäßig das Dateidienstprogramm von Linux.
Wenn ein Benutzer derzeit ein Formular mit falschen Daten sendet, wird das Formular mit den oben angegebenen Fehlern erneut angezeigt. Das Problem ist jedoch, dass das angehängte Bild verloren geht und der Benutzer es erneut auswählen muss. Dies ist sehr einfach zu beheben, indem ein weiteres Plugin namens cached_attachment_data verwendet wird:
Plugin: cached_attachment_data
Fügen Sie nun einfach ein verstecktes Feld in Ihr Formular ein.
<%= f.hidden_field :image, value: @photo.cached_image_data %> <%= f.label :image %> <%= f.file_field :image %>
Jetzt können Bilder hochgeladen werden, aber es gibt keine Möglichkeit, sie zu bearbeiten. Wir können sie also sofort korrigieren. Die entsprechenden Controller-Aktionen sind etwas trivial:
def edit @photo = Photo.find (params [: id]) ende def update @photo = Photo.find (params [: id]) wenn @ photo.update_attributes (photo_params) flash [: success] = 'Foto bearbeitet!' redirect_to photos_path else rendere 'edit' end end
Das Gleiche _bilden
teilweise wird verwendet:
Foto bearbeiten
<%= render 'form' %>
Schön, aber nicht genug: Nutzer können ein hochgeladenes Bild immer noch nicht entfernen. Um dies zuzulassen, müssen wir raten, was-ein weiteres Plugin:
plugin: remove_attachment
Es verwendet ein virtuelles Attribut namens :entferne Bild
, Erlaube es also im Controller:
def photo_params params.require (: photo) .permit (: title,: image,: remove_image) ende
Zeigen Sie jetzt ein Kontrollkästchen an, um ein Bild zu entfernen, wenn ein Datensatz einen Anhang enthält:
<% if @photo.image_data? %> Anlage entfernen: <%= f.check_box :remove_image %> <% end %>
Derzeit zeigen wir Originalbilder an, was für die Vorschau nicht der beste Weg ist: Fotos können groß sein und nehmen zu viel Platz ein. Natürlich können Sie einfach CSS verwenden Breite
und Höhe
Attribute, aber das ist auch eine schlechte Idee. Sie sehen, selbst wenn das Bild mit Stilen klein eingestellt ist, muss der Benutzer immer noch die Originaldatei herunterladen, die ziemlich groß sein kann.
Daher ist es viel besser, beim ersten Upload ein kleines Vorschaubild auf der Serverseite zu generieren. Dies beinhaltet zwei Plugins und zwei zusätzliche Edelsteine. Zuerst die Edelsteine fallen lassen:
gem "image_processing" gem "mini_magick", "> = 4.3.5"
Image_processing ist ein besonderer Edelstein, der vom Autor von Shrine erstellt wurde. Es werden einige Hilfsmethoden auf hoher Ebene zum Bearbeiten von Bildern vorgestellt. Dieses Juwel wiederum basiert auf mini_magick, einem Ruby-Wrapper für ImageMagick. Wie Sie sich schon gedacht haben, benötigen Sie ImageMagick auf Ihrem System, um diese Demo auszuführen.
Installiere diese neuen Edelsteine:
Bundle installieren
Fügen Sie nun die Plugins mit ihren Abhängigkeiten hinzu:
erfordern den ImageUploader der Klasse "image_processing / mini_magick" < Shrine include ImageProcessing::MiniMagick plugin :processing plugin :versions # other code… end
Die Verarbeitung ist das Plugin, mit dem wir ein Bild bearbeiten können (z. B. verkleinern, drehen, in ein anderes Format konvertieren usw.). Versionen wiederum erlauben es uns, ein Bild in verschiedenen Varianten zu haben. Für diese Demo werden zwei Versionen gespeichert: "Original" und "Daumen" (Größe geändert auf 300 x 300
).
Hier ist der Code zum Verarbeiten eines Bildes und zum Speichern seiner zwei Versionen:
Klasse ImageUploader < Shrine process(:store) do |io, context| original: io, thumb: resize_to_limit!(io.download, 300, 300) end end
resize_to_limit!
ist eine vom image_processing gem bereitgestellte Methode. Es verkleinert einfach ein Bild auf 300 x 300
wenn es größer ist und nichts tut, wenn es kleiner ist. Darüber hinaus bleibt das ursprüngliche Seitenverhältnis erhalten.
Wenn Sie nun das Bild anzeigen, müssen Sie entweder nur das Bild angeben :Original
oder :Daumen
Argument an die Bild URL
Methode:
<% if photo.image_data? %> <%= image_tag photo.image_url(:thumb) %> <% end %><%= photo.title %> | <%= link_to 'Edit', edit_photo_path(photo) %>
Das Gleiche kann innerhalb des Formulars gemacht werden:
<% if @photo.image_data? %> <%= image_tag @photo.image_url(:thumb) %> Anlage entfernen: <%= f.check_box :remove_image %> <% end %>
Um die verarbeiteten Dateien nach dem Hochladen automatisch zu löschen, können Sie ein Plugin mit dem Namen delete_raw hinzufügen:
Plugin: delete_raw
Abgesehen von dem Rendern eines Bildes können Sie auch die Metadaten abrufen. Lassen Sie uns zum Beispiel die Größe des Originalfotos und den MIME-Typ anzeigen:
<% if photo.image_data? %> <%= image_tag photo.image_url(:thumb) %>Größe <%= photo.image[:original].size %> Bytes
<% end %>
Mime Typ <%= photo.image[:original].mime_type %>
<%= photo.title %> | <%= link_to 'Edit', edit_photo_path(photo) %>
Was ist mit seinen Abmessungen? Leider werden sie nicht standardmäßig gespeichert. Dies ist jedoch mit einem Plugin namens store_dimensions möglich.
Das store_dimensions-Plugin ist auf den fastimage-Edelstein angewiesen. Schließen Sie ihn jetzt an:
Juwel "Fastimage"
Vergiss nicht zu laufen:
Bundle installieren
Nun fügen Sie einfach das Plugin hinzu:
plugin: store_dimensions
Und zeigen Sie die Abmessungen mit der Breite
und Höhe
Methoden:
<% if photo.image_data? %> <%= image_tag photo.image_url(:thumb) %>Größe <%= photo.image[:original].size %> Bytes
<% end %>
Mime Typ <%= photo.image[:original].mime_type %>
Maße <%= "#photo.image[:original].widthx#photo.image[:original].height" %><%= photo.title %> | <%= link_to 'Edit', edit_photo_path(photo) %>
Es gibt auch eine Maße
verfügbare Methode, die ein Array mit Breite und Höhe zurückgibt (z. B., [500, 750]
).
Entwickler wählen häufig Cloud-Dienste zum Hosten hochgeladener Dateien, und Shrine bietet eine solche Möglichkeit. In diesem Abschnitt zeige ich Ihnen, wie Sie Dateien zu Amazon S3 hochladen.
Als ersten Schritt fügen Sie zwei weitere Edelsteine in die Gemfile:
gem "aws-sdk", "~> 2.1" Gruppe: Entwicklung von "Dotenv-Schienen"
aws-sdk ist erforderlich, um mit dem SDK von S3 zu arbeiten, während dotenv-rail zum Verwalten von Umgebungsvariablen in der Entwicklung verwendet wird.
Bundle installieren
Bevor Sie fortfahren, sollten Sie ein Schlüsselpaar für den Zugriff auf S3 über die API erwerben. Melden Sie sich dazu bei Amazon Web Services Console an (oder melden Sie sich an) und navigieren Sie zu Sicherheitsnachweise> Benutzer. Erstellen Sie einen Benutzer mit Berechtigungen zum Bearbeiten von Dateien in S3. Hier ist die einfache Richtlinie, die vollen Zugriff auf S3 bietet:
"Version": "2016-11-14", "Statement": ["Effect": "Allow", "Action": "s3: *", "Resource": "*"]
Laden Sie das Schlüsselpaar des erstellten Benutzers herunter. Alternativ können Sie Root-Zugriffsschlüssel verwenden, aber ich stark entmutigen Sie machen das, weil es sehr unsicher ist.
Als Nächstes erstellen Sie einen S3-Bucket, um Ihre Dateien zu hosten, und fügen Sie im Stammverzeichnis des Projekts eine Datei hinzu, um Ihre Konfiguration zu hosten:
S3_KEY = YOUR_KEY S3_SECRET = YOUR_SECRET S3_BUCKET = YOUR_BUCKET S3_REGION = YOUR_REGION
Niemals jemals aussetzen Diese Datei der Öffentlichkeit zugänglich machen und sicherstellen, dass Sie sie von Git ausschließen:
.env
Ändern Sie nun die globale Konfiguration von Shrine und führen Sie einen neuen Speicher ein:
erfordern "Schrein" erfordern "Schrein / Speicher / s3" s3_options = access_key_id: ENV ['S3_KEY'], secret_access_key: ENV ['S3_SECRET'], Region: ENV ['S3_REGION'], Bucket: ENV ['S3_BUCKET'] , Shrine.storages = cache: Shrine :: Storage :: FileSystem.new ("public", Präfix: "uploads / cache"), store: Shrine :: Storage :: S3.new (Präfix: "store", ** s3_options),
Das ist es! An den anderen Teilen der App müssen keine Änderungen vorgenommen werden, und Sie können den neuen Speicher sofort testen. Wenn Sie von S3 Fehler erhalten, die sich auf falsche Schlüssel beziehen, stellen Sie sicher, dass Sie den Schlüssel und das Geheimnis genau kopiert haben, ohne nachgestellte Leerzeichen und unsichtbare Sonderzeichen.
Wir sind am Ende dieses Artikels angelangt. Hoffentlich fühlen Sie sich jetzt sehr zuversichtlich, Shrine zu verwenden und möchten es gerne in einem Ihrer Projekte einsetzen. Wir haben viele Funktionen dieses Edelsteins besprochen, aber es gibt noch mehr, wie die Möglichkeit, zusätzlichen Kontext zusammen mit Dateien und den direkten Upload-Mechanismus zu speichern.
Durchsuchen Sie daher die Dokumentation von Shrine und die offizielle Website, die alle verfügbaren Plugins ausführlich beschreibt. Wenn Sie weitere Fragen zu diesem Schmuckstück haben, zögern Sie nicht, sie zu veröffentlichen. Ich danke dir, dass du bei mir bleibst und wir sehen uns bald!