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.)

Respostas:


315

Tente o seguinte:

require 'open-uri'
open('image.png', 'wb') do |file|
  file << open('http://example.com/image.png').read
end

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]}")

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


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

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.


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.