#134 Paperclip
- Download:
- source codeProject Files in Zip (150 KB)
- mp4Full Size H.264 Video (11.5 MB)
- m4vSmaller H.264 Video (7.81 MB)
- webmFull Size VP8 Video (20.3 MB)
- ogvFull Size Theora Video (15.3 MB)
Qui sotto è riportata una pagina di un prodotto in un’applicazione di e-commerce. Vorremmo aggiungere un’immagine del prodotto a questa pagina e modificare il sistema di amministrazione in modo tale che si possa fare l’upload di un’immagine in fase di creazione o di modifica di un prodotto. In questo episodio vi mostreremo come usare un plugin chiamato Paperclip per questo scopo.
Paperclip semplifica l’aggiunta di allegati ai modelli. Lo useremo per aggiungere un campo al nostro modello Product
in modo che ciascun prodotto possa avere un’immagine associata.
Paperclip si installa come qualunque altro plugin. Dalla cartella radice della nostra applicazione lo possiamo installare da Github:
script/plugin install git://github.com/thoughtbot/paperclip.git
Aggiornare il modello
Ora che abbiamo installato Paperclip, possiamo lanciare il suo generatore per aggiungere un campo allegato al modello Product
:
script/generate paperclip product photo
Il generatore accetta due argomenti. Il primo è il nome del modello, nel nostro caso Product
, e il secondo è il nome che dovrà avere il nuovo campo di modello che conterrà l’allegato. Il generatore creerà una migration che aggiungerà quattro nuovi campi al modello:
add_column :products, :photo_file_name, :string add_column :products, :photo_content_type, :string add_column :products, :photo_file_size, :integer add_column :products, :photo_updated_at, :datetime
I quattro nuovi campi aggiunti dal generatore di Paperclip.
Dopodichè dobbiamo lanciare rake db:migrate
per aggiornare la tabella products sul database.
Il prossimo passo è aggiornare il codice del modello. Dobbiamo usare has_attached_file
per indicargli il nome del campo di allegato che abbiamo specificato quando abbiamo lanciato la migrazione:
class Product < ActiveRecord::Base belongs_to :category has_attached_file :photo end
Cambiare le viste
La form che crea o aggiorna un prodotto necessita dell’aggiunta di un campo per accettare il file da inviare:
<% form_for @product, :html => { :multipart => true } do |form| %> <ol class="formList"> <!-- Other fields go here... --> <li> <%= form.label :photo, "Photo" %> <%= form.file_field :photo %> <li> <%= form.submit "Submit" %> </li> </ol> <% end %>
Così come abbiamo dovuto aggiungere un file_field
alla form, dobbiamo anche modificare il form_for
per far sì che la form accetti degli allegati. Questo lo si fa aggiungendo :multipart => true
all’hash :html
, che fa sì che venga aggiunto l’attributo enctype="multipart/form-data"
al tag di apertura della form.
Naturalmente non ha senso permettere l’invio allegato di immagini se poi queste non vengono mostrate, per cui modifichiamo ora anche la vista show
. Per aggiungere un immagine dobbiamo solo aggiungere un image_tag
alla pagina. Il nostro modello Product
avrà ora un oggetto photo
come property con un metodo url
che ci darà il percorso corretto all’immagine.
<%= image_tag @product.photo.url %>
Fatto ciò possiamo modificare un prodotto, aggiungere un immagine a questo e vedere il risultato.
Ha funzionato! Il nostro prodotto ora ha un immagine, ma è un po’ troppo grande. Anche se possiamo controllare che siano allegate solamente immagini della dimensione corretta, sarebbe più semplice se potessimo ridimensionare le immagini sul server: con Paperclip c’è un modo per fare anche questo.
Ridimensionamento delle immagini
Il metodo has_attached_file
che abbiamo aggiunto al nostro modello Product
accetta una serie di opzioni. Una di queste è styles
, che ci permette di definire diverse dimensioni per la nostra immagine. Per creare una thumbnail per ogni immagine dobbiamo solo definire uno stile ed una dimensione specifica.
has_attached_file :photo, :styles => { :small => "150x150>" }
Con l’aggiunta del nuovo stile, Paperclip genererà ora una thumbnail di ciascuna immagine che stia dentro 150x150 pixel. Il simbolo > alla fine del valore di dimensione, indica a Paperclip di mantenere il rapporto fra le dimensioni dell’immagine, in modo che non risulti distorta dal ridimensionamento. Si noti che per abilitare il ridimensionamento, dovrete avere installato ImageMagick sul vostro server.
Per mostrare l’immagine ridimensionata nella vista show
del prodotto, dovremo cambiare l’image_tag
in modo che l’url punti alla versione più piccola.
<%= image_tag @product.photo.url(:small) %>
Se passiamo lo stile al metodo url
, verrà restituita l’immagine appropriata. L’immagine più piccola viene generata esclusivamente al momento dell’upload, per cui per ridimensionare la nostra foto, dovremo modificare il nostro prodotto e rieseguire l’upload del file. Una volta fatto, la foto del nostro prodotto apparirà alla dimensione di thumbnail che abbiamo specificato.
Impostare il percorso di Paperclip
Di default, Paperclip salva gli allegati nella cartella system
sotto la cartella public
dell’applicazione.
<img alt="Phone_large" src="http://asciicasts.com/system/photos/1/small/phone_large.jpg?1238845838" />
Paperclip crea una sua gerarchia per salvare gli allegati, creando cartelle in base all’id
del prodotto ed allo style
che abbiamo settato sul modello. La maggior parte delle volte, questa scelta può andar bene, ma se volessimo salvare le immagini da un’altra parte, dovremmo cambiare questo default.
Per salvare le immagini da un’altra parte aggiungiamo solamente due ulteriori opzioni al metodo has_attached_file, url e path:
has_attached_file :photo, :styles => { :small => "150x150>" }, :url => "/system/:attachment/:id/:style/:basename.:extension", :path => ":rails_root/public/system/:attachment/:id/:style/:basename.:extension"
Le chiavi url e path mostrate sopra sono i default usati da Paperclip. L’url è relativo alla cartella public
e ci sono dei placeholder nella stringa che rappresentano il nome del campo allegato, l’id
del modello e lo style. Ci sono placeholder analoghi nella stringa del path. Vogliamo salvare le nostre immagini in una cartella assets
, per cui cambiamo l’url e il path opportunamente:
has_attached_file :photo, :styles => { :small => "150x150>" }, :url => "/assets/products/:id/:style/:basename.:extension", :path => ":rails_root/public/assets/products/:id/:style/:basename.:extension"
Qualsiasi immagine che invieremo, ora sarà salvata nella cartella assets, anzichè nella system/photos.
Validazione degli allegati
Un’ultima utile funzione di Paperclip è quella che permette la validazione degli allegati inviati. Per validare le foto che vengono inviate, potremmo aggiungere dei validatori tipo questi alla nostra classe di modello Product
:
validates_attachment_presence :photo validates_attachment_size :photo, :less_than => 5.megabytes validates_attachment_content_type :photo, :content_type => ['image/jpeg', 'image/png']
Con i validatori di sopra, stiamo controllando che l’allegato ci sia sempre, che non sia più grande di cinque megabyte e che sia un’immagine o JPEG o PNG. Usando questi, possiamo validare un allegato in un modo semplice quanto la validazione di un qualunque altro campo. Una cosa su cui stare attenti, se si usa il controllo sul content type, è che Internet Explorer potrebbe riportare MIME types diversi da altri browser. Per esempio può trattare un file JPEG come image/pjpeg
piuttosto che come image/jpeg
.