Как я могу скачать файл с URL и сохранить его в Rails?

197

У меня есть URL-адрес изображения, которое я хочу сохранить локально, чтобы я мог использовать Paperclip для создания эскиза для своего приложения. Какой лучший способ загрузить и сохранить изображение? (Я изучал обработку файлов ruby, но ничего не нашел.)

Алок Суэйн
источник

Ответы:

315

Попробуй это:

require 'open-uri'
open('image.png', 'wb') do |file|
  file << open('http://example.com/image.png').read
end
Леви
источник
1
Это работает. Спасибо. Я попробовал это на изображении. Изображение не было правильно записано в файл. Как будто это было повреждено или что-то. Также не могли бы вы помочь мне сделать то же самое в приложении Rails. Могу ли я использовать это в приложении Rails?
Alok Swain
Да, вы можете использовать его в приложении рельсов. Файл не записывается должным образом, вероятно, потому что я забыл открыть место назначения в режиме записи в двоичном формате. Я отредактирую это сейчас.
Леви
78
Это читает весь файл в памяти. Лучший способ этоIO.copy_stream(open('http://example.com/image.png'), 'destination.png')
Янко-м
3
рельсы 5, 2016, мне не нужно require 'open-uri', просто использовал код под ним
Mirror318
1
этот ответ не работал для меня. правильный ответ здесь: stackoverflow.com/a/29743394/1536309
Блэр Андерсон
147

Еще более короткая версия:

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

Чтобы сохранить то же имя файла:

IO.copy_stream(download, "~/#{download.base_uri.to_s.split('/')[-1]}")
Клеменс Хелм
источник
2
И более эффективно, поскольку вывод не сохраняется в виде строки в памяти. +1
Итай Грудев
2
Хотя на самом деле полезно отображать оба ответа, люди, подобные мне, могут видеть оба, думать о различиях и затем сознательно выбирать этот ответ по правильным причинам :)
Максвелл Эванс
30

Если вы используете PaperClip, загрузка с URL-адреса теперь обрабатывается автоматически.

Предполагая, что у вас есть что-то вроде:

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

В вашей модели просто укажите изображение в виде URL-адреса, примерно так (написано намеренно):

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

Возможно, вы захотите поместить это в метод вашей модели. Это также будет отлично работать на временной файловой системе Heroku.

Скрепка возьмет это оттуда.

источник: документация по скрепке

superluminary
источник
4
Для будущих искателей Paperclip больше не позволяет это по умолчанию: medium.com/in-the-weeds/…
Alex Dunae
14

Я думаю, что это самый ясный способ:

require 'open-uri'

File.write 'image.png', open('http://example.com/image.png').read
Мудрец росс
источник
мудрец, я новичок в рельсах, где я могу добавить этот код в модель или контроллер или в поле зрения
adarsh
1
Это зависит, но обычно вы делаете что-то подобное внутри модели или метода контроллера. В контексте Rails вам, вероятно, лучше использовать инструменты инфраструктуры, такие как ActiveStorage, а не записывать напрямую на диск.
Мудрец Росс
10

Проверьте Net :: HTTP в стандартной библиотеке. В документации приведено несколько примеров загрузки документов с использованием HTTP.

Пяр Висландер
источник
2
Этот ответ требует большей наглядности, поскольку Kernel#openпозволяет не только получить доступ к файлу, но и вызвать процесс, добавив префикс символа канала (например, open("| ls")). Таким образом, это может привести к серьезной угрозе безопасности, если использовать переменные для ввода аргумента Kernel#open.
ConorB