Ruby Diary #26: Dove salvare le immagini in Rails
Mercoledì 2 Gennaio 2008 - 10:35
di Simone Carletti

Non ho aspettato più di qualche ora ad introdurre >respond_to() nell’applicazione Rails. Nel mio caso utilizzo un unico metodo per mostrare un’anteprima di una immagine. Se la richiesta è HTML mostro la cornice che impagina la thumbnail, in alternativa se la richiesta è di tipo immagine (png) restituisco l’immagine stessa. Per ogni altra richiesta restituisco 404.
A grandi linee, il codice assomiglia a questo:
def show
# validate URI
begin
@uri = URI.parse('http://' + params[:uri])
rescue
raise_404(); return
end
# more code here and get image_path
respond_to do |type|
# html request
type.html { render } # default template
# image requests
type.png { send_file(image_path, :disposition => 'inline') }
# all
type.all { raise_404(); return }
end
end
Come potete notare, utilizzo send_file() per inviare il contenuto del file e non fornisco direttamente il suo percorso per motivi di sicurezza. Questo approccio funziona però ad una condizione, ovvero che il controller che gestisce l’immagine — nel mio caso show — si trovi al di fuori di public/images.
public/images è infatti una cartella speciale il Rails. I file contenuti all’interno non sono soggetti a routing ma vengono direttamente restituiti al client.
Attenzione quindi. Se scriverete nel vostro file config/routes.rb una regola tipo
# display image map.image '/images/thubmnail/:uri', :controller => 'thumbnail', :action => 'show'
non verrà mai eseguita con una configurazione di Rails predefinita. O almeno, questo mi risulta al momento. L’accendiamo?
Commenti
1
Si, in realtà questo ragionamento funziona per tutto quanto si trovi nella sottocartella ‘public’; questo spiega anche il funzionamento del più semplice sistema di caching presente in Rails, che non fà altro che salvare l’output del rendering in un file all’interno della cartella public in modo che sia raggiungibile direttamente dal webserver senza l’intervento del framework.
# - postato da Sandro Paganotti - 04 Gennaio 2008 - 09:53
2
In realtà i file nella cartella ‘public’ evitano l’esecuzione di action tramite routing, ma qualsiasi richiesta è soggetta a routing se necessario.
Nel file config/routes.rb:
map.image 'images/thumbnails/:url.:format', :controller => 'thumbnail', :action => 'show'Nel file ‘app/controllers/thumbnails_controller.rb:
def show raise "Sono nel controller con filename " params[:filename] " e format " params[:format] endOra da browser accedendo a
http://localhost:3000/images/t....._rocks.png
passiamo per il controller:RuntimeError in ThumbnailController#show Sono nel controller con filename rails_rocks e format png ... Request Parameters: {"format"=>"png", "filename"=>"rails_rocks"}Come giustamente dicevate la cartella public viene controllata per verificare se è presente un file statico da servire a fronte di una richiesta; se il file non viene trovato ActionPack individua tramite il file ‘config/routes.rb’ controller, action e parametri da invocare per rispondere alla richiesta.
Per sanità mentale ti consiglierei di dedicare la cartella ‘public/images’ a file statici di immagini e cambiare il route del tuo controller.
A meno che tu non possa creare i thumbnail proattivamente come file statici (ad esempio quando viene caricata un’immagine sul server viene creato anche il rispettivo thumbnail) e che i file non possano essere resi pubblici.
In questo caso depositerei i thumbnails nella cartella /images/thumbnails/ con un bel File.open o qualcosa di simile così da sfruttare eventuali configurazioni del web server e il sistema di distribuzione degli asset su più server resa disponibile in Rails > 2 (che funziona davvero bene).







