9

私は両方を使用するモデルを持っています: 店舗の写真用の Carrierwave とPaperTrailバージョン管理用です。

また、更新時にさまざまなファイルを保存するようにCarrierwaveを構成しました(これは、写真のバージョンを変更したいためです)config.remove_previously_stored_files_after_update = false

問題はPaperTrail、単なる文字列 (URL となる) ではなく、写真 (CarrierWave Uploader) から Ruby オブジェクト全体を保存しようとすることです。

(バージョン テーブル、列オブジェクト)

---
first_name: Foo
last_name: Bar
photo: !ruby/object:PhotoUploader
  model: !ruby/object:Bla
    attributes:
      id: 2
      first_name: Foo1
      segundo_nombre: 'Bar1'
      ........

写真バージョンに単純な文字列を保存するには、どうすればこれを修正できますか?

4

6 に答える 6

10

バージョン管理されたモデルをオーバーライドできるitem_before_changeため、アップローダーアクセサーを直接呼び出さずwrite_attributeに代わりに使用できます。別の方法として、複数のモデルに対してこれを実行したい場合があるため、次のようにメソッドに直接モンキー パッチを適用できます。

module PaperTrail
  module Model
    module InstanceMethods
      private
        def item_before_change
          previous = self.dup
          # `dup` clears timestamps so we add them back.
          all_timestamp_attributes.each do |column|
            previous[column] = send(column) if respond_to?(column) && !send(column).nil?
          end
          previous.tap do |prev|
            prev.id = id
            changed_attributes.each do |attr, before|
              if defined?(CarrierWave::Uploader::Base) && before.is_a?(CarrierWave::Uploader::Base)
                prev.send(:write_attribute, attr, before.url && File.basename(before.url))
              else
                prev[attr] = before
              end
            end
          end
        end
    end
  end
end

それが最善の解決策かどうかはわかりませんが、うまくいくようです。

于 2012-02-25T00:47:10.333 に答える
6

これは問題を処理するためのより良い方法だと思うので、答えとして@beardeddのコメントを追加します。

データベースの列に次のような名前を付けてpicture_filenameから、モデルでアップローダを次のようにマウントします。

class User < ActiveRecord::Base has_paper_trail mount_uploader :picture, PictureUploader, mount_on: :picture_filename end

モデルにアクセスするために引き続きuser.picture.url属性を使用しますが、PaperTrail はリビジョンを の下に保存しpicture_filenameます。

于 2015-02-25T07:52:23.523 に答える
1

これは私にとって実際に機能するものです。これを config/initializers/paper_trail/.rb に置きます

module PaperTrail
  module Reifier
    class << self
      def reify_attributes(model, version, attrs)
        enums = model.class.respond_to?(:defined_enums) ? model.class.defined_enums : {}
        AttributeSerializers::ObjectAttribute.new(model.class).deserialize(attrs)
        attrs.each do |k, v|

          is_enum_without_type_caster = ::ActiveRecord::VERSION::MAJOR < 5 && enums.key?(k)

          if model.send("#{k}").is_a?(CarrierWave::Uploader::Base)
            if v.present?
               model.send("remote_#{k}_url=", v["#{k}"][:url])
               model.send("#{k}").recreate_versions!
            else
               model.send("remove_#{k}!")
            end
          else
              if model.has_attribute?(k) && !is_enum_without_type_caster
                model[k.to_sym] = v
              elsif model.respond_to?("#{k}=")
                model.send("#{k}=", v)
              elsif version.logger
                version.logger.warn(
                  "Attribute #{k} does not exist on #{version.item_type} (Version id: #{version.id})."
                )
              end
            end
        end
      end
    end
  end
end

これは S3 + heroku で動作するように reify メソッドをオーバーライドします

アップローダが更新または削除されたレコードから古いファイルを保持するには、アップローダでこれを行います

configure do |config|
   config.remove_previously_stored_files_after_update = false
end
def remove!
   true
end

次に、古いファイルを時々クリアするルーチンを作成します。幸運を祈ります

于 2016-12-20T20:55:28.670 に答える
0

@ショールズ・プロブースト

PaperTrail::Model::InstanceMethodsモジュールのpt_recordable_objectメソッドもオーバーライドする必要があります。

  def pt_recordable_object
    attr = attributes_before_change
    object_attrs = object_attrs_for_paper_trail(attr)

    hash = Hash[
        object_attrs.to_hash.map do |k, value|
          [k, value.is_a?(CarrierWave::Uploader::Base) ? value.url && File.basename(value.url) : value ]
        end
    ]

    if self.class.paper_trail_version_class.object_col_is_json?
      hash
    else
      PaperTrail.serializer.dump(hash)
    end
  end
于 2016-02-11T08:16:16.790 に答える