私はついにこれを機能させることができました。Taavoの答えは私を正しい方向に導きましたが、期待どおりには機能しませんでした.
主な問題は、 StringIO.new(icon_data) がno implicit conversion of nil into string
エラーを出し続けることでした。かなり掘り下げた後、StringIOに属性として追加する必要があることがわかりましたoriginal_filename
が、クラスにモンキーパッチを適用せずにこれを受け入れなくなってからずっと経ちました。Carrierwave wiki psge: How to: Upload from a string in Rails 3からこの問題の解決策を見つけました。
これでアイコンをファイルシステムに保存できるようになりましたが、不思議なことに、Version.icon フィールドに参照が入力されていませんでした (Version.apk は問題なく入力されました)。
結局、それを機能させるには、コールバックを取り除きbefore_Save :assign_icon
、コードを ApkUploader ファイルに移動する必要がありました。
私のコードは次のようになります。
1) StringIO を継承する新しいイニシャライザを作成
config/initializers/stringiohax.rb
class AppSpecificStringIO < StringIO
attr_accessor :filepath
def initialize(*args)
super(*args[1..-1])
@filepath = args[0]
end
def original_filename
File.basename(filepath)
end
end
2) アップローダーのマウント
アプリ/モデル/バージョン.rb
class Version < ActiveRecord::Base
mount_uploader :apk, ApkUploader
mount_uploader :icon, IconUploader
3) APK からデータを抽出し、アイコン属性を保存する
アプリ/モデル/バージョン.rb
class ApkUploader < CarrierWave::Uploader::Base
include Sprockets::Rails::Helper
include CarrierWave::MimeTypes
require 'ruby_apk'
..
...
process :extract_apk_info
def store_dir
app = App.find(model.app_id)
studio_name = Studio.find(app.studio_id).slug
"uploads/#{studio_name}/#{app.id}/version_#{model.version_code}"
end
def extract_apk_info
apk = Android::Apk.new(model.apk.path.to_s)
manifest = apk.manifest
icons = apk.icon
icon_name = icons.keys.last
icon_data = icons.values.last
model.package_name = manifest.package_name
model.version_code = manifest.version_code
model.version_name = manifest.version_name
model.min_sdk_ver = manifest.min_sdk_ver
model.icon = AppSpecificStringIO.new(icon_name, icon_data)
end