我有一个具有多个版本的App模型
版本模型包含apk
和icon
字段(等等)。
我目前有一个表单,允许用户使用carrierwave(class VersionUploader < CarrierWave::Uploader::Base
)上传.apk文件。
上传apk文件后,我已使用ruby_apk gem提取图标(来自versions_uploader.rb
内)。
对于图标,ruby_apk gem返回以下格式的哈希数组
{ "res/drawable-hdpi/ic_launcher.png" => "\x89PNG\x0D\x0A...", ... }
我想将图标保存到磁盘,并且可以像访问apk文件一样访问它(通过这个我的意思是可以调用像version.icon.identifier这样的东西)
我现在已经坚持了一段时间。任何有关如何完成或最佳方法的帮助将不胜感激。
提前致谢!
答案 0 :(得分:1)
如果您使用两个不同的上传器,并从模型层设置图标数据,这将变得更加容易。模型代码可能如下所示:
mount_uploader :apk, ApkUploader
mount_uploader :icon, IconUploader
before_save :assign_icon
def assign_icon
if apk_changed?
icon_data = Android::Apk.new(apk.path).icons.values.first
self.icon = StringIO.new(icon_data)
end
end
请注意,before_save
必须在mount_uploader :apk
之后,因为mount_uploader
在before_save
事件上创建了its own callbacks,并且您希望在它们之后触发。< / p>
答案 1 :(得分:0)
我终于设法让这个工作了。 Taavo的回答让我朝着正确的方向前进,但它并没有像预期的那样发挥作用。
主要问题是StringIO.new(icon_data)一直给我no implicit conversion of nil into string
错误。经过一番挖掘后,我发现我需要将original_filename
作为属性添加到StringIO中,但它早已停止接受这一点而没有猴子修补类。我从Carrierwave wiki psge找到了解决这个问题的方法:How to: Upload from a string in Rails 3。
现在让我将图标保存到文件系统,但神秘的是,没有使用引用填充Version.icon字段(Version.apk填充没有任何问题)。
最后,为了让它工作,我不得不摆脱before_Save :assign_icon
回调并将我的代码移到ApkUploader文件中。
我的代码看起来像这样:
1)创建了一个继承自StringIO
的新初始化程序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)装载上传者
class Version < ActiveRecord::Base
mount_uploader :apk, ApkUploader
mount_uploader :icon, IconUploader
3)从APK中提取数据并保存图标属性
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