Rails 中使用 Paperclip 存 URI 附件

使用 Rails APP + Paperclip Gem 做附件存取系統,靜態檔案的資料夾格式預設是跟著 id 跑( /000/000/000/ 九碼化的 ID 切成 3 階資料夾),最近因為要做資料庫合併,大批的資料會被賦予新的 ID,原先放在 AWS S3 上面的靜態資料夾結構就會 mapping 錯誤,必須要依照新的 ID 去存放相對應的資料夾結構。

由於部分圖片附件在存取時還會同步進行縮圖,如果要用 s3-cmd 這類的外部工具直接搬資料,得連各種不同 model 的縮圖定義一起處理,痛苦指數不低。

原先預計要從 HTTP GET request 的 response body 裡直接塞 tempfile :

url = 'https://s3.amazonaws.com'
path = '/BUCKET-NAME/MODEL/ATTACHMENT/000/016/222/original/FILE.jpg'
conn = Faraday.new(:url => url) do |faraday|
  faraday.request  :url_encoded
  faraday.response :logger
  faraday.adapter  Faraday.default_adapter
end

response = conn.get path
model.attachment = response.body

一直噴出各式各樣無法存入或者檔案格式錯誤的錯誤訊息。

試過自行重組檔案的檔頭 :

attachment_file = {
  :filename => /^.*\/(.*\..*)$/.match(uri)[1].split('?').first,
  :type => response.headers['content-type'],
  :headers => response.headers,
  :tempfile => response.body
}

model.attachment = attachment_file

一樣過不了 Paperclip 的檔案驗證機制。

使用 File.new(response.body)File.new(attachment_file)ActionDispatch::Http::UploadedFile.new(attachment_file) 都解析不了檔案。

撞了好一會牆後,發現 Paperclip 吃 URI object。一切的撞牆只要簡單的:

url = 'https://s3.amazonaws.com'
path = '/BUCKET-NAME/MODEL/ATTACHMENT/000/016/222/original/FILE.jpg'

model.attachment = URI.parse("#{url}#{path}")

獻給其他可能要做這類奇異操作的破頭工程師們。