Search code examples
ruby-on-railsversionpaper-trail-gem

Rails model versioning - one model with independently versioned columns


I have a model for a multilingual website with wiki functionality which contains various fields I wish to have versioned, however I need to revert changes made to some columns but not others.

For example, I store the English and Spanish versions of a written guide for each model instance.

Imagine:

  • User A edits the Spanish guide and adds profanity
  • User B later edits the English guide and makes useful changes.

Typically versioning means that reverting the changes made by user A also will revert later changes by User B, despite the fact that in my case these are two separate concerns.

So I need to essentially have scoped version histories. For example using papertrail:

#guide.rb
has_paper_trail :only => [:en_title, :en_body]
has_paper_trail :only => [:es_title, :es_body]

Any easiest solution for this? I really don't want to move my guides into separate models with a one to one relationship just to achieve this.


Solution

  • Although I'd personally extract translations into their own model to avoid this, you should still be able to achieve this without too much trickery.

    PaperTrail creates a new Version object every time a record is changed. Every version is accessible through the object.versions array.

    You'll have to come up with a way to decide which attribute you want to revert and which version you want to revert it back to. Once you have this, reverting it shouldn't be very difficult.

    For example, in your model:

    # Arguments:
    #   attr - Must respond to to_s with name of attribute to revert
    #   ver  - Integer (e.g. -1 for previous version) or actual Version object
    def revert_attribute(attr, ver)
      ver = self.versions[ver] if ver.class == Integer
      ver = ver.reify
      self.write_attribute( attr, ver.read_attribute(attr) )
      self.save
    end
    

    Code isn't tested or syntax checked, but ought to work from what I've seen in the PaperTrail source.

    It's not a perfectly integrated solution, but it should be adequate for most needs.