PAPERCLIP – Fotoupload

In diesem Tutorial programmieren wir einen Bilderupload mit Ruby On Rails und dafür verwenden wir das „Paperclip“ Gem.

Legen wir also mit einer neuen Ruby On Rails Applikation. Ich verwende hier wie immer die Entwicklungsumgebung von Cloud9. Dazu einfach hier einen neuen Arbeitsplatz erstellen „Create a workspace“. Ich nennen diesen Kontainer einmal „bilderhost“, wähle hier Ruby On Rails aus und erstelle den Arbeitsplatz. Solltest du unter Linux/Windows/MacOSX arbeiten dann geht dies über den Befehl rails new appname → rails new bilderhost.

Der Kontainer ist nun erstellt und wir prüfen zuerst einmal unsere Applikation ob diese einwandfrei erstellt worden ist. Dazu klicken wir einfach auf den Run Button bei Cloud9 oder über den Terminal/Konsole rails server. Bei Cloud9 wird automatisch eine Domain erstellt und darüber können wir auf unsere App zugreifen. Wie wir sehen unsere Applikation ist erfolgreich erstellt worden.

Begeben wir uns zurück in die Entwicklungsumgebung und stoppen den Server erst einmal. Was wir hier jetzt im Terminal / Konsole jetzt machen werden, wir erstellen mit Hilfe von Scaffolding einfach nur ein paar Post, also die Struktur für Post mit einem Titel und einem Content.

rails generate scaffold posts title:string content:string

Die Scaffolding Struktur sorgt eben schon dafür, dass die Views wie beispielsweise index, edit, show, new bereits mit integriert sind. Nicht vergessen, dadurch dass wir auch Datentypen haben, wird hier auch eine Migration der Datenbank erstellt. Dies sehen wir unter db/migrate/ und diesen Inhalt (title, content) möchten wir ja dann bei jedem Post in unserer Datenbank speichern. Also die Migration nicht vergessen!

rake db:migrate

Dadurch haben wir die Daten migriert und in unserer Datenbank sind nun diese Felder vorhanden. Jetzt wir doch gleich die Applikation einmal und sollten dadurch eine Struktur mit Posts finden. Diese Struktur ermöglicht uns ja bereits das Scaffolding in Ruby On Rails.

localhost:3000/posts 

Hier können wir über den „New Post“ Button nun einen neuen Post erstellen. Gebe dazu einfach deinen Titel und deine Beschreibung ein und klicke auf „Create Post“. Da wir hier unter Listing Posts später auch unsere Bilder angezeigt haben möchten werden wir diese Seite nun als Startseite festlegen.

Aktuell ist unsere Startseite unserer Ruby On Rails Applikation per default „Welcome aboard, you are riding Ruby On Rails“. Wir begeben uns zum Ändern in config/routes.rb und hier fügen wir eine neue Zeile hinzu.

root 'posts#index'

Nach der Änderung speichern wir dies und können unsere App direkt aktualisieren. Nun sehen wir sofort, dass unsere Startseite die „Listing Posts“-Seite ist und ein navigieren auf „/posts“ nicht mehr notwendig ist. Die angelegten Posts können wir uns anzeigen lassen oder diese auch direkt zerstören.

Kommen wir nun zum Kerninhalt dieses Tutorials, dem Bilderupload in Ruby On Rails. Dies bedeutet, dass wir zu jedem Post dann ein Bild anfügen können. Da wir uns ja im Entwicklungsmodus begeben, also innerhalb der Cloud oder auf unserem eigenen PC, benötigen wir eine Software für den Datei-Upload. Denn wir möchten nicht nur, dass unser Bild erfolgreich hochgeladen wird, sondern auch in verschiedenen Auflösungen abgespeichert werden kann. Hier kommt ImageMagick ins Spiel. ImageMagick kann ganz einfach innerhalb von Cloud9 eingebunden werden, dazu sind folgende Befehle notwendig:

sudo apt-get update
Dadurch wird unser Ubuntu Kontainer aktualisiert. Und nachdem das Update erfolgreich war, installieren wir die ImageMagick Software.
sudo apt-get install imagemagick

Somit wird nun die ImageMagick Software in unserer Ruby On Rails Entwicklungsumgebung installiert. Diese Software ist also nicht innerhalb unserer Rails App installiert, denn dies würde über das gemfile gesehen. Bei Hostern wie Heroku ist ImageMagick bereichts von Hausaus installiert.

Wir sind nun also bereit um das eigentliche Gem „Paperclip“ in unsere App zu integrieren und begeben uns in unser Gemfile.

gem "paperclip", git: "git://github.com/thoughtbot/paperclip.git"

bundle install

Aus der Dokumentation können wir entnehmen, dass wir unser Post-Model anpassen müssen. Dazu begeben wir uns in app/models/posts.rb und hier ändern wir den Beispielcode der Paperclip Dokumentation leicht ab.

user → posts
avatar → image

app/views/models/post.rb
class Post < ActiveRecord::Base
  has_attached_file :image, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
  validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
endr

 

Um nun auch unsere Datenbank für den Bilderupload entsprechend zu erweitern, verwenden wir den Rails migration generator:

app/views/posts/_form.html.erb
rails generate paperclip user image
rake db:migrate

Nachdem wir die Installation von Paperclip abgeschlossen haben und uns auf die „New Post“ Seite unserer App begeben, dann erkennen wir, dass es keine Möglichkeit gibt ein Bild hochzuladen. Diese Funktion können wir über das Form im Posts Ordner hinzufügen.

app/views/posts/_form.html.erb
<%= form_for @post, url: posts_path, html: { multipart: true } do |f| %>
  <% if @post.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>
 
      <ul>
      <% @post.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
  <div class="field">
    <%= f.label :image %><br>
    <%= f.file_field :image %>
  </div>
  <div class="field">
    <%= f.label :title %><br>
    <%= f.text_field :title %>
  </div>
  <div class="field">
    <%= f.label :content %><br>
    <%= f.text_field :content %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Das Absenden des Formulars inklusive der Auswahl eines Bildes ist nun möglich, jedoch wird uns das Bild innerhalb unserer Ruby On Rails Applikation nicht angezeigt. Wir begeben uns zurück in die Dokumentation von Paperclip und finden unter „Show View“ den Beispielcode für das Anzeigen der Bilder.

<p>  
 <%= image_tag @post.image.url(:medium) %>
</p>

Diesen Code fügen wir in app/views/posts/show.html.erb ein. Dadurch sollte nun das Bild auch angezeigt werden. Nachdem wir die Webseite aber aktualisiert haben, erkennen wir sofort, dass uns ein „Missing Image“ angezeigt wird. In der Dokumentation von Paperclip wird auf die Einstellungen des Controllers hingewiesen. Ruby On Rails erlaubt durch die so genannten „Strong Parameters“ nur eine Whitelist an Parametern, dies heißt für uns, dass wir die post_params in unserem Posts Controller entsprechend anpassen müssen.

Sowohl die create als auch die update Methode greifen auf die post_params zurück. Diese Parameter finden wir in als private Methode vor und hier erweitern wir title und content um unser image Objekt:

app/controllers/posts_controller.rb
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
  params.require(:post).permit(:title, :content, :image)
endr

Unser hochgeladenes Bild wird also nun optimal dargestellt. Wo speichert aber die App eigentlich das Bild? Hierzu begeben wir uns einmal in den Ordner public/system/images/ und arbeiten uns durch die Struktur. Wir stellen fest, dass verschiedene Ordner mit der Auflösung des Bildes angelegt wurden. Solltest deine App mit vielen Bildern arbeiten, dann ist es nicht zum empfehlen den Bilderupload in deiner App zu haben. Ich empfehle diese Datenlast auszulagern an beispielsweise ein Amazon S3 Bucket, dadurch ist die Ruby On Rails Applikation und die Verwaltung der Bilder klar von einander getrennt.

Begeben wir uns nun einmal auf unsere Webseite und wie wir sehen wird aktuell noch kein Vorschaubild angezeigt. Dies ändern wir nun indem wir in die Schleife die Anweisung für Paperclip einfügen. Als Größe verwenden wir hier „thumb“. 

app/views/posts/index.html.erb
<table>
  <thead>
    <tr>
      <th>Title</th>
      <th>Content</th>
      <th colspan="3"></th>
    </tr>
  </thead>
 
  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td><%= post.title %></td>
        <td><%= image_tag post.image.url(:thumb) %></td>
        <td><%= post.content %></td>
        <td><%= link_to 'Show', post %></td>
        <td><%= link_to 'Edit', edit_post_path(post) %></td>
        <td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

Soviel zum Paperclip Gem und der Möglichkeit einen Bilderupload in deine Ruby On Rails Applikation zu integrieren.