Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Papertrail and Carrierwave

I have a model that use both: Carrierwave for store photos, and PaperTrail for versioning.

I also configured Carrierwave for store diferent files when updates (That's because I want to version the photos) with config.remove_previously_stored_files_after_update = false

The problem is that PaperTrail try to store the whole Ruby Object from the photo (CarrierWave Uploader) instead of simply a string (that would be its url)

(version table, column object)

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

How can I fix this to store a simple string in the photo version?

like image 981
eveevans Avatar asked Feb 23 '12 23:02

eveevans


2 Answers

You can override item_before_change on your versioned model so you don't call the uploader accesor directly and use write_attribute instead. Alternatively, since you might want to do that for several models, you can monkey-patch the method directly, like this:

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

Not sure if it's the best solution, but it seems to work.

like image 115
rabusmar Avatar answered Oct 25 '22 15:10

rabusmar


Adding @beardedd's comment as an answer because I think this is a better way to handle the problem.

Name your database columns something like picture_filename and then in your model mount the uploader using:

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

You still use the user.picture.url attribute to access your model but PaperTrail will store revisions under picture_filename.

like image 42
Gerry Shaw Avatar answered Oct 25 '22 13:10

Gerry Shaw