0

私は has_many Versions の App モデルを持っています Versions モデルにはapkiconフィールドがあります (とりわけ)。

現在、ユーザーが Carrierwave ( ) を使用して .apk ファイルをアップロードできるフォームを持っていますclass VersionUploader < CarrierWave::Uploader::Base

apk ファイルがアップロードされたら、ruby_apk gem を使用してアイコンを抽出しました (内からversions_uploader.rb)。

アイコンの場合、ruby_apk gem は次の形式でハッシュの配列を返します

{ "res/drawable-hdpi/ic_launcher.png" => "\x89PNG\x0D\x0A...", ... }

アイコンをディスクに保存し、apk ファイルと同じ方法でアクセスできるようにしたいと思います (つまり、version.icon.identifier などを呼び出すことができるということです)。

私はしばらくこれにこだわっています。それをどのように行うべきか、またはどのアプローチが最適かについての助けをいただければ幸いです。

前もって感謝します!

4

2 に答える 2

1

2 つの異なるアップローダーを使用し、モデル レイヤーからアイコン データを設定すると、これは非常に簡単になります。モデル コードは次のようになります。

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 :apkmount_uploaderbefore_save

于 2013-08-23T21:58:47.880 に答える
0

私はついにこれを機能させることができました。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
于 2013-08-24T16:40:03.830 に答える