Upload souboru v Ruby on Rails

Včera v noci jsem si trochu pohrával s frameworkem Ruby on Rails. Je to vlastně první pidiaplikace, kterou jsem v railsech vytvořil a musím říct, že po celodenní píííp s píííp Java „Enterprise“ frameworky, servery a dalšími píííp to bylo příjemné programování.

Takže… nebudu popisovat jak si vytvořit kostru projektu, vytvoření databáze, nastartování Mongrelu… podobných návodů jsou stovky a navíc použití nějakého IDE vám tyhle věci usnadní. Já pořád ještě nevím, jestli je lepší Aptana (Eclipse + RadRails plugin) a nebo NetBeans, ale včera to celé vzniklo v beta verzi NetBeans 6.5.

Co to vlatně umí? Nic moc, umí to načíst soubor (obrázek), uložit do databáze, zase ho z té databáze načíst, zmenšit (změnit velikost) a zobrazit. Je to jenom minimální varianta, takže se zde nekontrolují vstupní data ani nic jiného, prostě jenom ukázka toho, jak to celé funguje.

Předpokládám, že máte nastavenou databázi (já použil MySQL) a pomocí gem nainstalované railsy a také rmagick, což je Ruby rozhraní pro ImageMagick.

Pro vytvoření modelu můžeme využít migrace. A ty je zase pro změnu dobré si nechat vygenerovat, takže:

$ script/generate migration create_image

To vygeneruje jednak model, tak také migraci. Do té stačí doplnit jediný řádek - položku pro uložení dat souboru. Výsledek bude vypadat nějak takto:

class CreateImages < ActiveRecord::Migration
  def self.up
    create_table :images do |t|
      t.binary :data, :limit => 16_777_215
      t.timestamps
    end
  end

  def self.down
    drop_table :images
  end
end

Pomocí příkazu rake db:migrate pak vytvoříme tabulku v databázi. Další krok bude vytvoření controleru. Ten bude mít tři metody - index, ta bude sloužit pro zobrazení formuláře pro upload souboru, metoda upload bude zajišťovat uložení načteného souboru do databáze a následě ho zobrazí (do view vrstvy předá id obrázku) a metoda image, která podle id najde obrázek v databázi, načte ho, změní velikost a pošle na výstup. Všimněte si jak málo kódu stačí (všímají si zejména javisté, programátoři v „plain PHP“ si všímají naopak použití relačního mapování, oddělení view vrstvy apod. ;-).

require 'RMagick'

class UploadController < ApplicationController

  def index
  end

  def upload
    im = Image.new
    im.data = params[:upload]['image'].read
    im.save
    @id = im.id
  end

  def image
    image = Image.find(params[:id])

    im = Magick::Image.from_blob(image.data).first;
    res_im = im.resize(200,100);

    send_data(res_im.to_blob,
                   :type => "image/jpg",
                   :filename => "jmenosouboru",
                   :disposition => 'inline')
  end
end

Asi na tom není co vysvětlovat, všechno je krásně čitelné. Pro jistotu připomínám, že objekt Image se vygeneroval automaticky během migrace. Poslední co chybí, je view vrstva, budeme potřebovat soubor pro zobrazení formuláře index.rhtml

<h1>File Upload</h1>

<% form_tag({:action => 'upload'}, :multipart => true) do %>
<%= file_field 'upload', 'image' %>
<%= submit_tag "Upload" %>
<% end %>

a soubor upload.rhtml pro zobrazení výledku.

<%= image_tag("/upload/image/#{@id}", :alt => "Image") %>

A to je všechno. Ze začátku to působí trochu jako magie, ale není to tak hrozné. S čím se nějak nemůžu sžít je styl šablon, dal bych přednost kombinaci HTML a vlastních tagů, ale třeba něco podobného existuje. Uvedený příklad je moje řešení daného problému, uvítám, když v něm někdo najde chybu a upozorní mě na ni.

Zanechte, prosím, komentář

 
 

This is a captcha-picture. It is used to prevent mass-access by robots. (see: www.captcha.net)

Musíte opsat těchto 5 znaků (číslice 0..9 a písmena A..F), a odeslat formulář.

  

Nemohu to přečíst. Prosím vygenerovat