Object versioning in Rails, like Papertrail but in

2019-03-15 06:28发布

问题:

For a project I'm currently working on I need to implement object versioning. Unfortunately I need to keep a full history of each object, so a single table solution like Papertrail would quickly become un-manageable. There are features of Papertrail which I like, however, which I haven't been able to find in a solution with individual tables for each model (such as acts_as_versioned).

  • Ability to store meta-information from both controller and model
  • Data is serialized so schema changes don't modify the version table
  • Powerful methods for traversing versions
  • Automatic tracking of change responsibility

There are also some features which Papertrail does not have which would be bonuses:

  • Built-in version diff support
  • Differential instead of full versions

I am currently considering forking Papertrail to use individual tables for each model, but would like to save that effort if there's an existing solution.

Update: Vestal Versions by default uses a single table, but by providing a custom version class for each model and using the "set_table_name" method of ActiveRecord, I was able to create separate tables for each model. Vestal Versions also has built in diff support, though its interface isn't as powerful as Papertrails. It also lacks association support.

Update 2: As papertrail seems to be a more active project I've forked the gem and added in custom class support similar to vestal versions which now allows for the ability to define separate tables per model. My fork is here, but I hope it will be pulled into the main project repository shortly. https://github.com/benzittlau/paper_trail

回答1:

You can specify custom version subclasses with the :class_name option:

class Post < ActiveRecord::Base
  has_paper_trail :class_name => 'PostVersion'
end

class PostVersion < Version
  # custom behaviour, e.g:
  self.table_name = :post_versions # in rails 2, use set_table_name
end

This allows you to store each model's versions in a separate table, which is useful if you have a lot of versions being created.



回答2:

I've been using Vestal Versions, a rails gem/plugin that uses the memento pattern to create a history table, and it saves a diff of attributes in after_save and after_destroy callbacks.

It also records when it was changed and increments a version number so you can rollback to a certain version or a version present at a certain date or time.

I can then pull up an object like so:

@user = User.last
@user.versions.last.changes #=> {:name => ['Robert','Bob']}

I'm a pretty big fan.