2011-02-27 12 views
24

Quindi questo dovrebbe essere abbastanza semplice, ma non riesco a farlo funzionare.Rendering di un'immagine

Ho un metodo controller che trova un'immagine basata su una query, quindi l'output viene memorizzato nella cache. L'immagine potrebbe essere remota (flickr, immagini google, ecc.) O potrebbe essere locale. Indipendentemente dalla fonte, ho solo bisogno di prendere il contenuto del file immagine e passarlo all'utente. In sostanza, un proxy. Passare attraverso le immagini remote sembra funzionare bene, ma passare attraverso le immagini locali mi dà un:

invalid byte sequence in UTF-8 

Quindi ecco cosa ho ottenuto. Spero che qualcuno possa risolvere il problema o guidarmi in una direzione migliore con il mio codice.

def image_proxy 
    query = params[:query] 
    image_url = get_image_url(query) # returns an absolute local file path or a URL 

    response.headers['Cache-Control'] = "public, max-age=#{12.hours.to_i}" 
    response.headers['Content-Type'] = 'image/jpeg' 
    response.headers['Content-Disposition'] = 'inline' 
    render :text => open(image_url).read 
end 

I file remoti funzionano correttamente, i file locali no.

bonus a tutti coloro che possono aiutare a risolvere questo altro problema:

  1. ho bisogno di impostare il tipo di contenuto corretto. Gli URL delle immagini remote non mi dicono il tipo di immagine, ho solo un URL e talvolta l'url non contiene un'estensione. Quindi ho scelto jpeg perché sembra funzionare a prescindere dal tipo di immagine che mi è stato inviato.

Grazie!

risposta

23

Provare a utilizzare render :text => open(image_url, "rb").read, che indica a Ruby che il file che apre è binario e non provare a leggerlo come testo.

modificare

Per la domanda di bonus, è possibile leggere i primi byte e guardare a ciò che essi contengono. Un PNG inizia sempre con i valori di byte esadecimali 89 50 4E 47 0D 0A 1A 0A (oi valori decimali 137 80 78 71 13 10 26 10).

Wikipedia ha un list of magic numbers used to identify file che puoi guardare. Basta creare un metodo di qualche tipo che legge i primi pochi byte e lo confronta con quello.

+0

Ottima risposta, ha funzionato perfettamente. –

14

Quale versione di Rails? Per Rails 3, dovresti guardare gli streaming methods che sono stati aggiunti. send_data sarebbe il modo corretto di inviare dati binari. Se le immagini sono locali e il tuo server web lo supporta, puoi utilizzare send_file che non bloccherà l'istanza di un binario mentre l'utente scarica un'immagine.

+1

Sì, 'send_data' è ciò che vuoi, non' render'. – aceofspades

Problemi correlati