Renderizando uma imagem

Então isso deve ser bem fácil, mas eu não consigo fazer funcionar.

Eu tenho um método controlador que encontra uma imagem com base em uma consulta e, em seguida, a saída fica em cache. A imagem pode ser remota (flickr, google images, etc) ou pode ser local. Independentemente da fonte, eu só preciso pegar o conteúdo do arquivo de imagem e passá-lo para o usuário. Em essência, um proxy. Passar por imagens remotas parece funcionar bem, mas passar por imagens locais me dá um:

invalid byte sequence in UTF-8 

Então aqui está o que eu tenho. Espero que alguém possa resolver o problema ou me guiar em uma direção melhor com meu código.

 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 

Arquivos remotos funcionam bem, arquivos locais não funcionam.

Bônus para qualquer um que possa ajudar a resolver esse outro problema:

  1. Eu preciso definir o tipo de conteúdo adequado. URLs de imagens remotas não me dizem o tipo de imagem, apenas recebo um URL e, às vezes, o URL não contém uma extensão. Então eu peguei jpeg porque parece funcionar, independentemente do tipo de imagem enviado para mim.

Obrigado!

Tente usar render :text => open(image_url, "rb").read , que diz ao Ruby que o arquivo que ele abre é binário e não tenta lê-lo como texto.

editar

Para a questão bônus, você pode ler os primeiros bytes e ver o que eles contêm. Um PNG começará sempre com os valores dos bytes hexadecimais 89 50 4E 47 0D 0A 1A 0A (ou os valores decimais 137 80 78 71 13 10 26 10).

A Wikipedia tem uma lista de números mágicos usados ​​para identificar arquivos que você pode ver. Basta criar um método de algum tipo que leia os primeiros bytes e compare-o com isso.

Qual versão do Rails? Para o Rails 3, você deve observar os methods de streaming que foram adicionados. send_data seria a maneira correta de enviar dados binários. Se as imagens forem locais e o servidor da Web suportar, você poderá usar o send_file, que não bloqueará uma instância do rails enquanto o usuário fizer download de uma imagem.