Como posso baixar um arquivo de uma URL e salvá-lo no Rails?

197

Tenho um URL para uma imagem que desejo salvar localmente, para que eu possa usar o Paperclip para produzir uma miniatura para o meu aplicativo. Qual é a melhor maneira de baixar e salvar a imagem? (Examinei o tratamento de arquivos ruby, mas não encontrei nada.)

Alok Swain
fonte

Respostas:

315

Tente o seguinte:

require 'open-uri'
open('image.png', 'wb') do |file|
  file << open('http://example.com/image.png').read
end
Levi
fonte
1
Isso funciona. Obrigado. Eu tentei isso em uma imagem. A imagem não foi gravada corretamente no arquivo. Como se estivesse corrompido ou algo assim. Você também pode me orientar a fazer o mesmo em um aplicativo Rails. Posso usar isso em um aplicativo Rails?
Alok Swain
Sim, você pode usá-lo em um aplicativo de trilhos. O arquivo que não está sendo gravado corretamente é provavelmente porque eu esqueci de abrir o destino no modo binário de gravação. Vou editar isso agora.
Levi
78
Isso lê o arquivo inteiro na memória. A melhor maneira éIO.copy_stream(open('http://example.com/image.png'), 'destination.png')
janko-m
3
Trilhos 5, 2016, eu não precisava require 'open-uri', apenas utilizado o código sob ele
Mirror318
1
esta resposta não funcionou para mim. A resposta correta está aqui: stackoverflow.com/a/29743394/1536309
Blair Anderson #
147

Uma versão ainda mais curta:

require 'open-uri'
download = open('http://example.com/image.png')
IO.copy_stream(download, '~/image.png')

Para manter o mesmo nome de arquivo:

IO.copy_stream(download, "~/#{download.base_uri.to_s.split('/')[-1]}")
Elmo de Clemens
fonte
2
E mais eficiente, pois a saída não é armazenada como uma string na memória. +1
Itay Grudev 3/16/16
2
Embora seja realmente útil tendo ambas as respostas apresentadas, para que as pessoas como eu pode ver tanto, pensar sobre as diferenças e depois escolher esta resposta conscientemente pelas razões certas :)
Maxwell Evans
30

Se você estiver usando o PaperClip, o download de um URL agora será tratado automaticamente.

Supondo que você tenha algo como:

class MyModel < ActiveRecord::Base
  has_attached_file :image, ...
end

No seu modelo, basta especificar a imagem como uma URL, algo como isto (escrito à mão e deliberadamente):

@my_model = MyModel.new
image_url = params[:image_url]
@my_model.image = URI.parse(image_url)

Você provavelmente desejará colocar isso em um método em seu modelo. Isso também funcionará bem no sistema de arquivos temporário do Heroku.

O clipe de papel irá levá-lo a partir daí.

fonte: documentação do clipe de papel

superluminário
fonte
4
Para futuros pesquisadores, o Paperclip não permite mais isso por padrão: medium.com/in-the-weeds/…
Alex Dunae
14

Eu acho que esta é a maneira mais clara:

require 'open-uri'

File.write 'image.png', open('http://example.com/image.png').read
Sage Ross
fonte
sábio eu sou novo para os trilhos, onde eu posso adicionar este código no modelo ou controlador ou na vista
adarsh
1
Depende, mas normalmente você faria algo assim dentro de um modelo ou método de controlador. No contexto do Rails, é provável que você use melhor as ferramentas da estrutura, como o ActiveStorage, em vez de gravar diretamente no disco.
Sábio Ross
10

Confira Net :: HTTP na biblioteca padrão. A documentação fornece vários exemplos de como baixar documentos usando HTTP.

Pär Wieslander
fonte
2
Essa resposta precisa de mais visibilidade, pois Kernel#openpermite não apenas o acesso ao arquivo, mas também a chamada do processo, prefixando um símbolo de barra vertical (por exemplo, open("| ls")). Portanto, isso pode levar a um sério risco à segurança usando entrada variável no argumento de Kernel#open.
ConorB