[英]Resizing image using file_column - loses image quality using Rails
[英]How do I download a remote image from another site to a file_column in Ruby on Rails?
第一個問題,希望我不會弄糟:)
Ruby on Rails的新手(也是Ruby新手),並且偶然發現了應用程序預期行為的問題。
我在屬於模型產品的模型圖片中有一個file_column:image,它可以包含許多圖片。
file_column在使用時工作得很好,因為我認為這是要使用的,並且使用<%= file_column_field“ picture”,“ image”%>等來上傳圖像。那部分工作得很好。
問題在於要有一個文本字段,以便用戶可以在其站點上為圖像標簽輸入css-選擇器(他們已經注冊了該站點以及應該放置圖像的頁面的路徑)。 我一直無法弄清楚如何從“其他”網站上正確下載該圖像。
使用這兩種方法都將導致“不知道如何處理帶有值'GIF89ad .....”的字符串,后跟“二進制”的負載。
方法1:
url = URI.parse(picture_www.external_url)
Net::HTTP.start(url.host, url.port) {|http|
resp = http.get(url.path)
picture_www.image = resp.body unless resp.nil?
}
方法2:
res = open(picture_www.external_url)
picture_www.image = res.read unless res.nil?
external_url包含正確的url,下載正常,因此問題似乎出在我試圖將圖像分配給file_column字段的方式中。 自然地,問題可能出在我下載圖像的方式上,我不知道問題出在哪里,實際上是TBH ... :)
有人可以幫助我嗎?
更新:
嘗試使用臨時文件“導致未定義的方法'original_filename'為”等
Net::HTTP.start(url.host, url.port) {|http|
resp = http.get(url.path)
tempfile = Tempfile.new('test.jpg')
File.open(tempfile.path, 'wb') do |f|
f.write resp.body
end
picture_www.image = tempfile unless resp.nil?
}
更新2:
調試顯示,當我創建的臨時文件沒有時,上載的文件在@_dc_obj和@tmpfile下具有@content_type(例如,“ image / jpeg”)屬性和@original_path(無路徑的文件名)屬性。 正確設置這些設置也許會使這項工作成功? 如何正確設置? 如果正確設置這些值,是否可以“正確”完成文件下載? 當我得到一個可行的解決方案后,當然要對代碼進行重組。
更新3:
從Minver的答案中,我得到了“ original_filename”問題的解決方案,此代碼似乎有效:
io = open(picture_www.external_url)
def io.original_filename; base_uri.path.split('/').last; end
io.original_filename.blank? ? nil : io
picture_www.image = io
雖然不知道這是否是執行此操作的“正確”方法,但這是我現在將要使用的方法,除非出現某些“顯然正確的執行方法”解決方案:)
-普考
Joe Martinez的UrlUpload方法是一個很好的解決方案,但是代碼缺少關鍵方法。 如果您超越了method_missing ,那么您也應該始終超越對response_to?的要求。 方法。 在這種情況下,這尤其重要,因為某些軟件使用了response_to ?? 在決定是否要進行多篇文章時。
例如,法拉第(Faraday)寶石執行以下操作:
def has_multipart?(body)
body.values.each do |v|
if v.respond_to?(:content_type)
return true
elsif v.respond_to?(:values)
return true if has_multipart?(v)
end
end
false
end
因此,如果您要使用上面的UrlUpload代碼,建議您添加以下方法:
def respond_to?(symbol)
attachment_data.respond_to?(symbol) || super
end
然后,法拉第和其他相關的寶石將能夠使用此類的實例來生成適當的multipart-post。
你去
require 'open-uri'
class UrlUpload
EXTENSIONS = {
"image/jpeg" => ["jpg", "jpeg", "jpe"],
"image/gif" => ["gif"],
"image/png" => ["png"]
}
attr_reader :original_filename, :attachment_data
def initialize(url)
@attachment_data = open(url)
@original_filename = determine_filename
end
# Pass things like size, content_type, path on to the downloaded file
def method_missing(symbol, *args)
if self.attachment_data.respond_to? symbol
self.attachment_data.send symbol, *args
else
super
end
end
private
def determine_filename
# Grab the path - even though it could be a script and not an actual file
path = self.attachment_data.base_uri.path
# Get the filename from the path, make it lowercase to handle those
# crazy Win32 servers with all-caps extensions
filename = File.basename(path).downcase
# If the file extension doesn't match the content type, add it to the end, changing any existing .'s to _
filename = [filename.gsub(/\./, "_"), EXTENSIONS[self.content_type].first].join(".") unless EXTENSIONS[self.content_type].any? {|ext| filename.ends_with?("." + ext) }
# Return the result
filename
end
end
# Make it always write to tempfiles, never StringIO
OpenURI::Buffer.module_eval {
remove_const :StringMax
const_set :StringMax, 0
}
我不知道,但是也許這就是您想要的。 保存圖像時,請提供一個css_selector並獲取一個圖像文件作為回報。
這是視圖:
<%= form_for(@image) do |f| %>
<div class="field">
<%= f.label :css_selector %><br />
<%= f.text_field :css_selector %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
這是模型:
class Picture < ActiveRecord::Base
require 'open-uri' # Required to download the photo
require 'mechanize' # Good gem to parse html pages
belongs_to :product
# Define the css_selector (not required as a filed in the database)
attr_accessor :css_selector
# Before we save the image, we download the photo if image has a css_selector value
before_save :download_remote_photo, :if => :css_selector_provided?
private
# Check if the attribute is provided
def css_selector_provided?
!self.css_selector.blank?
end
# This method opens the page where the photo is
# and grab the url to the image using a css-selector
def fetch_photo_url
agent = Mechanize::new
page = agent.get(HERE_IS_THE_URL_TO_THE_PAGE_YOU_WANNA_SCRAPE)
doc = Nokogiri::HTML(page.body)
image_element = doc.at_css(self.css_selector) # Get the image on that page using the css selector
image_url = image_element[:src]
end
def download_remote_photo
self.image = do_download_remote_photo(fetch_photo_url)
end
def do_download_remote_photo(photo_url)
io = open(URI.parse(URI.escape(photo_url)))
def io.original_filename; base_uri.path.split('/').last; end
io.original_filename.blank? ? nil : io
rescue # catch url errors with validations instead of exceptions (Errno::ENOENT, OpenURI::HTTPError, etc...)
end
end
尚未測試代碼,但希望您能理解!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.