I was wondering whether the following use case can be achieved using the papertrail gem?
A Wikipedia-type of application with wiki pages that logged in users can change/edit and where:
Moderators can undo specific changes:
I understand papertrail allows to roll back to a previous version but what I’m asking here is somewhat different. That is, the ability to undo a specific edit/change. Suppose there have been three edits/versions to a record/wiki-page. Then if you want to undo edit 2, then changes from edit 1 and 3 should still remain. But if you would roll back to the version before edit 2, then also edit 3 would be undone, which is not what I want here.
Changes made (contributions) by a user feed back into the user’s profile, which would then have an overview of the changes/contributions made by that user:
I believe this is possible using the --with-changes
option (which registers the change that was made in addition to the full dump of the changed resource) in combination with the fact that papertrail registers the user who has made a change. Am I correct in my understanding?
In the tutorial http://samurails.com/gems/papertrail/ I read about using papertrail in combination with the gem diffy
to establish what was changed exactly, but what I don’t understand is why the tutorial uses diffy
when papertrail itself already offers a “diffing” functionality?
To have moderators first accept a change by some users, before that change is actually implemented (i.e., before the change is actually applied):
Can papertrail also help to achieve this functionality?
1. Moderators can undo specific changes
You can achieve this functionality using the following module:
module Revertible
SKIP_FIELDS = [ 'updated_at' ]
def revert_to(version)
raise 'not version of this model' unless self == version.item
changes = version.changeset.select{ |k, v| not SKIP_FIELDS.include?(k) }.map{ |k,v| [k.to_sym, v[0]] }.to_h
self.update_attributes(changes)
end
end
It adds revert_to
method to the model which allows moderator to undo only changes in specific edit. Pay attention to SKIP_FIELDS
array, which excludes several system fields, which should not be reverted.
We can easily test this module. Let's create a table:
create_table :articles do |t|
t.string :title
t.string :body
t.timestamps null: false
end
and associated model:
class Article < ActiveRecord::Base
include Revertible
has_paper_trail
end
The following test case shows, that only version specific edits were reverted:
class ArticleTest < ActiveSupport::TestCase
test "rollback specific edit" do
article = Article.create(title: 'My Article 1', body: 'first version')
article.update_attributes(title: 'My Article 1', body: 'second version')
article.update_attributes(title: 'My Article 3', body: 'third version')
assert_equal 3, article.versions.count
assert_equal 'My Article 3', article.title
assert_equal 'third version', article.body
article.revert_to article.versions[1]
assert_equal 4, article.versions.count
assert_equal 'My Article 3', article.title # title haven't changed
assert_equal 'first version', article.body # body did change
end
end
2.Changes made (contributions) by a user
To turn on changes tracking add the following method to your application controller:
class ApplicationController
def user_for_paper_trail
user = current_user
return 'public' if user.blank?
user.username
end
end
Changes made by a specific user can be easily tracked now:
versions = PaperTrail::Version.where(whodunnit: 'dimakura')
version = versions.first
version.item # => #<Article id: 1, title: "...", body: "...">
version.event # => "create"
version.changeset
Diffy
As to your question about diffy
. You don't actually need it if the only thing you need is to get difference between two adjacent versions. But if you need to compare changes between version separated by several edits, then you do need diffy
or any similar library.
Moderator accepts changes
I don't think it's easy to implement in a single field. You probably need to have two columns for "accepted" and "raw" data, maybe even two different models.
I think I covered all you questions and it was helpful for you.