Jak mogę pobrać plik z adresu URL i zapisać go w Railsach?

197

Mam adres URL obrazu, który chcę zapisać lokalnie, dzięki czemu mogę użyć Paperclip do utworzenia miniatury dla mojej aplikacji. Jaki jest najlepszy sposób na pobranie i zapisanie obrazu? (Zajrzałem do obsługi plików ruby, ale niczego nie spotkałem.)

Alok Swain
źródło

Odpowiedzi:

315

Spróbuj tego:

require 'open-uri'
open('image.png', 'wb') do |file|
  file << open('http://example.com/image.png').read
end
Levi
źródło
1
To działa. Dzięki. Próbowałem tego na zdjęciu. Obraz nie został poprawnie zapisany w pliku. Jakby został uszkodzony lub coś takiego. Czy mógłbyś też poprowadzić mnie do zrobienia tego samego w aplikacji Rails. Czy mogę tego użyć w aplikacji Rails?
Alok Swain
Tak, możesz go użyć w aplikacji szynowej. Plik nie został poprawnie zapisany, prawdopodobnie dlatego, że zapomniałem otworzyć miejsce docelowe w trybie binarnym zapisu. Będę to teraz edytować.
Levi
78
Odczytuje to cały plik z pamięci. Najlepszym sposobem jestIO.copy_stream(open('http://example.com/image.png'), 'destination.png')
janko-m
3
szyny 5, 2016, nie musiałem require 'open-uri', po prostu użyłem kodu pod nim
Mirror318
1
ta odpowiedź nie działała dla mnie. poprawna odpowiedź jest tutaj: stackoverflow.com/a/29743394/1536309
Blair Anderson
147

Jeszcze krótsza wersja:

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

Aby zachować tę samą nazwę pliku:

IO.copy_stream(download, "~/#{download.base_uri.to_s.split('/')[-1]}")
Clemens Helm
źródło
2
I bardziej wydajne, ponieważ dane wyjściowe nie są przechowywane jako ciąg w pamięci. +1
Itay Grudev
2
Mimo że przydaje się wyświetlanie obu odpowiedzi, aby ludzie tacy jak ja mogli zobaczyć obie, pomyśl o różnicach, a następnie świadomie wybierz tę odpowiedź z właściwych powodów :)
Maxwell Evans
30

Jeśli używasz PaperClip, pobieranie z adresu URL jest teraz obsługiwane automatycznie.

Zakładając, że masz coś takiego:

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

W swoim modelu po prostu określ obraz jako adres URL, coś w tym stylu (napisane celowo):

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

Prawdopodobnie będziesz chciał umieścić to w metodzie w swoim modelu. Będzie to również działać dobrze na tymczasowym systemie plików Heroku.

Spinacz zabierze go stamtąd.

źródło: dokumentacja spinacza

superluminarny
źródło
4
W przypadku przyszłych poszukiwaczy Paperclip nie zezwala już na to domyślnie: medium.com/in-the-weeds/…
Alex Dunae
14

Myślę, że jest to najwyraźniejszy sposób:

require 'open-uri'

File.write 'image.png', open('http://example.com/image.png').read
Sage Ross
źródło
mędrzec, jestem nowy w szynach, gdzie mogę dodać ten kod w modelu lub kontrolerze lub w widoku
adarsh
1
To zależy, ale zazwyczaj robisz coś takiego w metodzie modelu lub kontrolera. W kontekście Railsów lepiej jest używać narzędzi frameworka, takich jak ActiveStorage, zamiast pisać bezpośrednio na dysku.
Sage Ross,
10

Sprawdź Net :: HTTP w standardowej bibliotece. Dokumentacja zawiera kilka przykładów pobierania dokumentów za pomocą protokołu HTTP.

Pär Wieslander
źródło
2
Ta odpowiedź wymaga większej widoczności, ponieważ Kernel#openumożliwia nie tylko dostęp do pliku, ale także proces wywoływania przez prefiks symbolu potoku (np open("| ls").). Może więc prowadzić do poważnego zagrożenia bezpieczeństwa, stosując zmienne dane wejściowe do argumentu Kernel#open.
ConorB