mongoid-history 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +15 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +101 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/lib/mongoid/history/trackable.rb +150 -0
- data/lib/mongoid/history/tracker.rb +67 -0
- data/lib/mongoid/history.rb +12 -0
- data/lib/mongoid-history.rb +7 -0
- data/mongoid-history.gemspec +91 -0
- data/spec/integration/integration_spec.rb +264 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/trackable_spec.rb +71 -0
- data/spec/tracker_spec.rb +17 -0
- metadata +245 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.2@
|
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem 'easy_diff'
|
4
|
+
gem 'mongoid', '~> 2.0.0.rc.7'
|
5
|
+
|
6
|
+
group :development do
|
7
|
+
gem "rspec", "~> 2.3.0"
|
8
|
+
gem "yard", "~> 0.6.0"
|
9
|
+
gem "bundler", "~> 1.0.0"
|
10
|
+
gem "jeweler", "~> 1.5.2"
|
11
|
+
gem "rcov", ">= 0"
|
12
|
+
gem "reek", "~> 1.2.8"
|
13
|
+
gem "roodi", "~> 2.1.0"
|
14
|
+
gem "database_cleaner"
|
15
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Aaron Qian
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
= mongoid-history
|
2
|
+
|
3
|
+
In frustration of Mongoid::Versioning, I created this plugin for tracking historical changes for any document, including embedded ones. It achieves this by storing all history tracks in a single collection that you define. (See Usage for more details) Embedded documents are referenced by storing an association path, which is an array of document_name and document_id fields starting from the top most parent document and down to the embedded document that should track history.
|
4
|
+
|
5
|
+
This plugin implements multi-user undo, which allows users to undo any history change in any order. Undoing a document also creates a new history track. This is great for auditing and preventing vandalism, but it is probably not suitable for use cases such as a wiki.
|
6
|
+
|
7
|
+
== Install
|
8
|
+
|
9
|
+
gem install mongoid-history
|
10
|
+
|
11
|
+
== Rails 3
|
12
|
+
|
13
|
+
In your Gemfile:
|
14
|
+
|
15
|
+
gem 'mongoid-history'
|
16
|
+
|
17
|
+
== Usage
|
18
|
+
|
19
|
+
Here is a quick example on how to use this plugin. For more details, please look at spec/integration/integration_spec.rb. It offers more detailed examples on how to use Mongoid::History.
|
20
|
+
|
21
|
+
# Create a new class for tracking all histories.
|
22
|
+
# Must include Mongoid::History::Tracker
|
23
|
+
class HistoryTracker
|
24
|
+
include Mongoid::History::Tracker
|
25
|
+
end
|
26
|
+
|
27
|
+
class Post
|
28
|
+
include Mongoid::Document
|
29
|
+
include Mongoid::Timestamps
|
30
|
+
|
31
|
+
# History tracking all Post Documents
|
32
|
+
# Note: Tracking will not work until #track_history is invoked
|
33
|
+
include Mongoid::History::Trackable
|
34
|
+
|
35
|
+
field :title
|
36
|
+
field :body
|
37
|
+
field :rating
|
38
|
+
embeds_many :comments
|
39
|
+
|
40
|
+
# Telling Mongoid::History how you want to track
|
41
|
+
track_history :on => [:title, :body], # I want to track title and body fields only. Default is :all
|
42
|
+
:modifier_field => :modifier, # Adds "referened_in :modifier" to track who made the change. Default is :modifier
|
43
|
+
:version_field => :version, # Adds "field :version, :type => Integer" to track current version. Default is :version
|
44
|
+
:track_create => false, # Do you want to track document creation? Default is false
|
45
|
+
end
|
46
|
+
|
47
|
+
class Comment
|
48
|
+
include Mongoid::Document
|
49
|
+
include Mongoid::Timestamps
|
50
|
+
|
51
|
+
# Declare that we want to track comments
|
52
|
+
include Mongoid::History::Trackable
|
53
|
+
|
54
|
+
field :title
|
55
|
+
field :body
|
56
|
+
embedded_in :post, :inverse_of => :comments
|
57
|
+
|
58
|
+
# Track title and body for all comments, scope it to post (the parent)
|
59
|
+
# Also track creation
|
60
|
+
track_history :on => [:title, :body], :scope => :post, :track_create => true
|
61
|
+
end
|
62
|
+
|
63
|
+
# The modifier can be specified as well
|
64
|
+
class User
|
65
|
+
include Mongoid::Document
|
66
|
+
include Mongoid::Timestamps
|
67
|
+
|
68
|
+
field :name
|
69
|
+
end
|
70
|
+
|
71
|
+
user = User.create(:name => "Aaron")
|
72
|
+
post = Post.create(:title => "Test", :body => "Post", :modifier => user)
|
73
|
+
comment = post.comments.create(:title => "test", :body => "comment", :modifier => user)
|
74
|
+
comment.history_tracks.count # should be 1
|
75
|
+
|
76
|
+
comment.update_attributes(:title => "Test 2")
|
77
|
+
comment.history_tracks.count # should be 2
|
78
|
+
|
79
|
+
track = comment.history_tracks.last
|
80
|
+
|
81
|
+
track.undo! # comment title should be "Test"
|
82
|
+
|
83
|
+
track.redo! # comment title should be "Test 2"
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
== Contributing to mongoid-history
|
88
|
+
|
89
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
90
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
91
|
+
* Fork the project
|
92
|
+
* Start a feature/bugfix branch
|
93
|
+
* Commit and push until you are happy with your contribution
|
94
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
95
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
96
|
+
|
97
|
+
== Copyright
|
98
|
+
|
99
|
+
Copyright (c) 2011 Aaron Qian. See LICENSE.txt for
|
100
|
+
further details.
|
101
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "mongoid-history"
|
16
|
+
gem.homepage = "http://github.com/aq1018/mongoid-history"
|
17
|
+
gem.license = "MIT"
|
18
|
+
gem.summary = %Q{ history tracking, auditing, undo, redo for mongoid}
|
19
|
+
gem.description = %Q{In frustration of Mongoid::Versioning, I created this plugin for tracking historical changes for any document, including embedded ones. It achieves this by storing all history tracks in a single collection that you define. (See Usage for more details) Embedded documents are referenced by storing an association path, which is an array of document_name and document_id fields starting from the top most parent document and down to the embedded document that should track history.
|
20
|
+
|
21
|
+
This plugin implements multi-user undo, which allows users to undo any history change in any order. Undoing a document also creates a new history track. This is great for auditing and preventing vandalism, but it is probably not suitable for use cases such as a wiki.}
|
22
|
+
gem.email = "aqian@attinteractive.com"
|
23
|
+
gem.authors = ["Aaron Qian"]
|
24
|
+
end
|
25
|
+
Jeweler::RubygemsDotOrgTasks.new
|
26
|
+
|
27
|
+
require 'rspec/core'
|
28
|
+
require 'rspec/core/rake_task'
|
29
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
30
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
31
|
+
spec.rspec_opts = "--color --format progress"
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
35
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
+
spec.rcov = true
|
37
|
+
spec.rcov_opts = "--exclude ~\/.rvm,spec"
|
38
|
+
end
|
39
|
+
|
40
|
+
require 'reek/rake/task'
|
41
|
+
Reek::Rake::Task.new do |t|
|
42
|
+
t.fail_on_error = true
|
43
|
+
t.verbose = false
|
44
|
+
t.source_files = 'lib/**/*.rb'
|
45
|
+
end
|
46
|
+
|
47
|
+
require 'roodi'
|
48
|
+
require 'roodi_task'
|
49
|
+
RoodiTask.new do |t|
|
50
|
+
t.verbose = false
|
51
|
+
end
|
52
|
+
|
53
|
+
task :default => :spec
|
54
|
+
|
55
|
+
require 'yard'
|
56
|
+
YARD::Rake::YardocTask.new
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,150 @@
|
|
1
|
+
module Mongoid::History
|
2
|
+
module Trackable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def track_history(options={})
|
7
|
+
model_name = self.name.tableize.singularize.to_sym
|
8
|
+
default_options = {
|
9
|
+
:on => :all,
|
10
|
+
:except => [:created_at, :updated_at],
|
11
|
+
:modifier_field => :modifier,
|
12
|
+
:version_field => :version,
|
13
|
+
:scope => model_name,
|
14
|
+
:track_create => false
|
15
|
+
}
|
16
|
+
|
17
|
+
options = default_options.merge(options)
|
18
|
+
|
19
|
+
# normalize except fields
|
20
|
+
# manually ensure _id, id, version will not be tracked in history
|
21
|
+
options[:except] = [options[:except]] unless options[:except].is_a? Array
|
22
|
+
options[:except] << options[:version_field]
|
23
|
+
options[:except] << "#{options[:modifier_field]}_id".to_sym
|
24
|
+
options[:except] += [:_id, :id]
|
25
|
+
options[:except] = options[:except].map(&:to_s).flatten.compact.uniq
|
26
|
+
options[:except].map(&:to_s)
|
27
|
+
|
28
|
+
# normalize fields to track to either :all or an array of strings
|
29
|
+
if options[:on] != :all
|
30
|
+
options[:on] = [options[:on]] unless options[:on].is_a? Array
|
31
|
+
options[:on] = options[:on].map(&:to_s).flatten.uniq
|
32
|
+
end
|
33
|
+
|
34
|
+
field options[:version_field].to_sym, :type => Integer
|
35
|
+
referenced_in options[:modifier_field].to_sym, :class_name => Mongoid::History.modifer_class_name
|
36
|
+
|
37
|
+
include InstanceMethods
|
38
|
+
extend SingletonMethods
|
39
|
+
|
40
|
+
delegate :history_trackable_options, :to => 'self.class'
|
41
|
+
|
42
|
+
before_update :track_update
|
43
|
+
before_create :track_create if options[:track_create]
|
44
|
+
|
45
|
+
|
46
|
+
Mongoid::History.trackable_classes ||= []
|
47
|
+
Mongoid::History.trackable_classes << self
|
48
|
+
Mongoid::History.trackable_class_options ||= {}
|
49
|
+
Mongoid::History.trackable_class_options[model_name] = options
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
module InstanceMethods
|
55
|
+
def history_tracks
|
56
|
+
@history_tracks ||= Mongoid::History.tracker_class.where(:scope => history_trackable_options[:scope], :association_chain => triverse_association_chain)
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
def should_track_update?
|
61
|
+
!modified_attributes_for_update.blank?
|
62
|
+
end
|
63
|
+
|
64
|
+
def triverse_association_chain(node=self)
|
65
|
+
list = node._parent ? triverse_association_chain(node._parent) : []
|
66
|
+
list << { 'name' => node.class.name, 'id' => node.id }
|
67
|
+
list
|
68
|
+
end
|
69
|
+
|
70
|
+
def modified_attributes_for_update
|
71
|
+
@modified_attributes_for_update ||= if history_trackable_options[:on] == :all
|
72
|
+
changes
|
73
|
+
else
|
74
|
+
changes.reject do |k, v|
|
75
|
+
!history_trackable_options[:on].include?(k)
|
76
|
+
end.reject do |k, v|
|
77
|
+
history_trackable_options[:except].include?(k)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def modified_attributes_for_create
|
83
|
+
@modified_attributes_for_create ||= attributes.inject({}) do |h, pair|
|
84
|
+
k,v = pair
|
85
|
+
h[k] = [nil, v]
|
86
|
+
h
|
87
|
+
end.reject do |k, v|
|
88
|
+
history_trackable_options[:except].include?(k)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def history_tracker_attributes
|
93
|
+
return @history_tracker_attributes if @history_tracker_attributes
|
94
|
+
|
95
|
+
@history_tracker_attributes = {
|
96
|
+
:association_chain => triverse_association_chain,
|
97
|
+
:scope => history_trackable_options[:scope],
|
98
|
+
:modifier => send(history_trackable_options[:modifier_field])
|
99
|
+
}
|
100
|
+
|
101
|
+
original, modified = transform_changes((new_record? ? modified_attributes_for_create : modified_attributes_for_update))
|
102
|
+
@history_tracker_attributes[:original] = original
|
103
|
+
@history_tracker_attributes[:modified] = modified
|
104
|
+
@history_tracker_attributes
|
105
|
+
end
|
106
|
+
|
107
|
+
def track_update
|
108
|
+
return unless should_track_update?
|
109
|
+
current_version = (self.send(history_trackable_options[:version_field]) || 0 ) + 1
|
110
|
+
self.send("#{history_trackable_options[:version_field]}=", current_version)
|
111
|
+
Mongoid::History.tracker_class.create!(history_tracker_attributes.merge(:version => current_version))
|
112
|
+
clear_memoization
|
113
|
+
end
|
114
|
+
|
115
|
+
def track_create
|
116
|
+
current_version = (self.send(history_trackable_options[:version_field]) || 0 ) + 1
|
117
|
+
self.send("#{history_trackable_options[:version_field]}=", current_version)
|
118
|
+
Mongoid::History.tracker_class.create!(history_tracker_attributes.merge(:version => current_version))
|
119
|
+
clear_memoization
|
120
|
+
end
|
121
|
+
|
122
|
+
def clear_memoization
|
123
|
+
@history_tracker_attributes = nil
|
124
|
+
@modified_attributes_for_create = nil
|
125
|
+
@modified_attributes_for_update = nil
|
126
|
+
@history_tracks = nil
|
127
|
+
end
|
128
|
+
|
129
|
+
def transform_changes(changes)
|
130
|
+
original = {}
|
131
|
+
modified = {}
|
132
|
+
changes.each_pair do |k, v|
|
133
|
+
o, m = v
|
134
|
+
original[k] = o if o
|
135
|
+
modified[k] = m if m
|
136
|
+
end
|
137
|
+
|
138
|
+
return original.easy_diff modified
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
module SingletonMethods
|
144
|
+
def history_trackable_options
|
145
|
+
@history_trackable_options ||= Mongoid::History.trackable_class_options[self.name.tableize.singularize.to_sym]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Mongoid::History
|
2
|
+
module Tracker
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
include Mongoid::Document
|
7
|
+
include Mongoid::Timestamps
|
8
|
+
|
9
|
+
field :association_chain, :type => Array, :default => []
|
10
|
+
field :modified, :type => Hash
|
11
|
+
field :original, :type => Hash
|
12
|
+
field :version, :type => Integer
|
13
|
+
field :scope, :type => String
|
14
|
+
referenced_in :modifier, :class_name => Mongoid::History.modifer_class_name
|
15
|
+
|
16
|
+
Mongoid::History.tracker_class_name = self.name.tableize.singularize.to_sym
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
end
|
22
|
+
|
23
|
+
def undo!
|
24
|
+
undo_hash = affected.easy_unmerge(modified)
|
25
|
+
undo_hash.easy_merge!(original)
|
26
|
+
trackable.update_attributes!(undo_hash)
|
27
|
+
end
|
28
|
+
|
29
|
+
def redo!
|
30
|
+
redo_hash = affected.easy_unmerge(original)
|
31
|
+
redo_hash.easy_merge!(modified)
|
32
|
+
trackable.update_attributes!(redo_hash)
|
33
|
+
end
|
34
|
+
|
35
|
+
def trackable
|
36
|
+
@trackable ||= trackable_parents_and_trackable.last
|
37
|
+
end
|
38
|
+
|
39
|
+
def trackable_parents
|
40
|
+
@trackable_parents ||= trackable_parents_and_trackable[0, -1]
|
41
|
+
end
|
42
|
+
|
43
|
+
def affected
|
44
|
+
@affected ||= (modified.keys | original.keys).inject({}){ |h,k| h[k] = trackable.attributes[k]; h}
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def trackable_parents_and_trackable
|
49
|
+
@trackable_parents_and_trackable ||= triverse_association_chain
|
50
|
+
end
|
51
|
+
|
52
|
+
def triverse_association_chain
|
53
|
+
chain = association_chain.dup
|
54
|
+
doc = nil
|
55
|
+
documents = []
|
56
|
+
begin
|
57
|
+
node = chain.shift
|
58
|
+
name = node['name']
|
59
|
+
col = doc.nil? ? name.classify.constantize : doc.send(name.tableize)
|
60
|
+
doc = col.where(:_id => node['id']).first
|
61
|
+
documents << doc
|
62
|
+
end while( !chain.empty? )
|
63
|
+
documents
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module History
|
3
|
+
mattr_accessor :tracker_class_name
|
4
|
+
mattr_accessor :trackable_classes
|
5
|
+
mattr_accessor :trackable_class_options
|
6
|
+
mattr_accessor :modifer_class_name
|
7
|
+
|
8
|
+
def self.tracker_class
|
9
|
+
@tracker_class ||= tracker_class_name.to_s.classify.constantize
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/mongoid/history')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/mongoid/history/tracker')
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/mongoid/history/trackable')
|
4
|
+
|
5
|
+
Mongoid::History.modifer_class_name = "User"
|
6
|
+
Mongoid::History.trackable_classes = []
|
7
|
+
Mongoid::History.trackable_class_options = {}
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{mongoid-history}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Aaron Qian"]
|
12
|
+
s.date = %q{2011-03-04}
|
13
|
+
s.description = %q{In frustration of Mongoid::Versioning, I created this plugin for tracking historical changes for any document, including embedded ones. It achieves this by storing all history tracks in a single collection that you define. (See Usage for more details) Embedded documents are referenced by storing an association path, which is an array of document_name and document_id fields starting from the top most parent document and down to the embedded document that should track history.
|
14
|
+
|
15
|
+
This plugin implements multi-user undo, which allows users to undo any history change in any order. Undoing a document also creates a new history track. This is great for auditing and preventing vandalism, but it is probably not suitable for use cases such as a wiki.}
|
16
|
+
s.email = %q{aqian@attinteractive.com}
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE.txt",
|
19
|
+
"README.rdoc"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
".rspec",
|
24
|
+
".rvmrc",
|
25
|
+
"Gemfile",
|
26
|
+
"LICENSE.txt",
|
27
|
+
"README.rdoc",
|
28
|
+
"Rakefile",
|
29
|
+
"VERSION",
|
30
|
+
"lib/mongoid-history.rb",
|
31
|
+
"lib/mongoid/history.rb",
|
32
|
+
"lib/mongoid/history/trackable.rb",
|
33
|
+
"lib/mongoid/history/tracker.rb",
|
34
|
+
"mongoid-history.gemspec",
|
35
|
+
"spec/integration/integration_spec.rb",
|
36
|
+
"spec/spec_helper.rb",
|
37
|
+
"spec/trackable_spec.rb",
|
38
|
+
"spec/tracker_spec.rb"
|
39
|
+
]
|
40
|
+
s.homepage = %q{http://github.com/aq1018/mongoid-history}
|
41
|
+
s.licenses = ["MIT"]
|
42
|
+
s.require_paths = ["lib"]
|
43
|
+
s.rubygems_version = %q{1.5.3}
|
44
|
+
s.summary = %q{history tracking, auditing, undo, redo for mongoid}
|
45
|
+
s.test_files = [
|
46
|
+
"spec/integration/integration_spec.rb",
|
47
|
+
"spec/spec_helper.rb",
|
48
|
+
"spec/trackable_spec.rb",
|
49
|
+
"spec/tracker_spec.rb"
|
50
|
+
]
|
51
|
+
|
52
|
+
if s.respond_to? :specification_version then
|
53
|
+
s.specification_version = 3
|
54
|
+
|
55
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
56
|
+
s.add_runtime_dependency(%q<easy_diff>, [">= 0"])
|
57
|
+
s.add_runtime_dependency(%q<mongoid>, ["~> 2.0.0.rc.7"])
|
58
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
|
59
|
+
s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
|
60
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
61
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
62
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
63
|
+
s.add_development_dependency(%q<reek>, ["~> 1.2.8"])
|
64
|
+
s.add_development_dependency(%q<roodi>, ["~> 2.1.0"])
|
65
|
+
s.add_development_dependency(%q<database_cleaner>, [">= 0"])
|
66
|
+
else
|
67
|
+
s.add_dependency(%q<easy_diff>, [">= 0"])
|
68
|
+
s.add_dependency(%q<mongoid>, ["~> 2.0.0.rc.7"])
|
69
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
70
|
+
s.add_dependency(%q<yard>, ["~> 0.6.0"])
|
71
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
72
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
73
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
74
|
+
s.add_dependency(%q<reek>, ["~> 1.2.8"])
|
75
|
+
s.add_dependency(%q<roodi>, ["~> 2.1.0"])
|
76
|
+
s.add_dependency(%q<database_cleaner>, [">= 0"])
|
77
|
+
end
|
78
|
+
else
|
79
|
+
s.add_dependency(%q<easy_diff>, [">= 0"])
|
80
|
+
s.add_dependency(%q<mongoid>, ["~> 2.0.0.rc.7"])
|
81
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
82
|
+
s.add_dependency(%q<yard>, ["~> 0.6.0"])
|
83
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
84
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
85
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
86
|
+
s.add_dependency(%q<reek>, ["~> 1.2.8"])
|
87
|
+
s.add_dependency(%q<roodi>, ["~> 2.1.0"])
|
88
|
+
s.add_dependency(%q<database_cleaner>, [">= 0"])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
@@ -0,0 +1,264 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Mongoid::History do
|
4
|
+
before :all do
|
5
|
+
class HistoryTracker
|
6
|
+
include Mongoid::History::Tracker
|
7
|
+
end
|
8
|
+
|
9
|
+
class Post
|
10
|
+
include Mongoid::Document
|
11
|
+
include Mongoid::Timestamps
|
12
|
+
include Mongoid::History::Trackable
|
13
|
+
|
14
|
+
field :title
|
15
|
+
field :body
|
16
|
+
field :rating
|
17
|
+
embeds_many :comments
|
18
|
+
track_history :on => [:title, :body]
|
19
|
+
end
|
20
|
+
|
21
|
+
class Comment
|
22
|
+
include Mongoid::Document
|
23
|
+
include Mongoid::Timestamps
|
24
|
+
include Mongoid::History::Trackable
|
25
|
+
|
26
|
+
field :title
|
27
|
+
field :body
|
28
|
+
embedded_in :post, :inverse_of => :comments
|
29
|
+
track_history :on => [:title, :body], :scope => :post, :track_create => true
|
30
|
+
end
|
31
|
+
|
32
|
+
class User
|
33
|
+
include Mongoid::Document
|
34
|
+
include Mongoid::Timestamps
|
35
|
+
|
36
|
+
field :name
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
before :each do
|
41
|
+
@user = User.create(:name => "Aaron")
|
42
|
+
@another_user = User.create(:name => "Another Guy")
|
43
|
+
@post = Post.create(:title => "Test", :body => "Post", :modifier => @user)
|
44
|
+
@comment = @post.comments.create(:title => "test", :body => "comment", :modifier => @user)
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "track" do
|
48
|
+
describe "on creation" do
|
49
|
+
it "should have one history track in comment" do
|
50
|
+
@comment.history_tracks.count.should == 1
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should assign title and body on modified" do
|
54
|
+
@comment.history_tracks.first.modified.should == {'title' => "test", 'body' => "comment"}
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should not assign title and body on original" do
|
58
|
+
@comment.history_tracks.first.original.should == {}
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
it "should assign modifier" do
|
63
|
+
@comment.history_tracks.first.modifier.should == @user
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should assigin version" do
|
67
|
+
@comment.history_tracks.first.version.should == 1
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should assigin scope" do
|
71
|
+
@comment.history_tracks.first.scope == "Post"
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should assigin association_chain" do
|
75
|
+
@comment.history_tracks.first.association_chain = [{:id => @post.id, :name => "Post"}, {:id => @comment.id, :name => "Comment"}]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "on update non-embedded" do
|
80
|
+
it "should create a history track if changed attributes match tracked attributes" do
|
81
|
+
lambda {
|
82
|
+
@post.update_attributes(:title => "Another Test")
|
83
|
+
}.should change(HistoryTracker, :count).by(1)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should not create a history track if changed attributes do not match tracked attributes" do
|
87
|
+
lambda {
|
88
|
+
@post.update_attributes(:rating => "untracked")
|
89
|
+
}.should change(HistoryTracker, :count).by(0)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should assign modified fields" do
|
93
|
+
@post.update_attributes(:title => "Another Test")
|
94
|
+
@post.history_tracks.first.modified.should == {
|
95
|
+
"title" => "Another Test"
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should assign original fields" do
|
100
|
+
@post.update_attributes(:title => "Another Test")
|
101
|
+
@post.history_tracks.first.original.should == {
|
102
|
+
"title" => "Test"
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should assign modifier" do
|
107
|
+
@post.update_attributes(:title => "Another Test")
|
108
|
+
@post.history_tracks.first.modifier.should == @user
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should assigin version on history tracks" do
|
112
|
+
@post.update_attributes(:title => "Another Test")
|
113
|
+
@post.history_tracks.first.version.should == 1
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should assigin version on post" do
|
117
|
+
@post.update_attributes(:title => "Another Test")
|
118
|
+
@post.version.should == 1
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should assigin scope" do
|
122
|
+
@post.update_attributes(:title => "Another Test")
|
123
|
+
@post.history_tracks.first.scope == "Post"
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should assigin association_chain" do
|
127
|
+
@post.update_attributes(:title => "Another Test")
|
128
|
+
@post.history_tracks.first.association_chain = [{:id => @post.id, :name => "Post"}]
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "on update non-embedded twice" do
|
133
|
+
it "should assigin version on post" do
|
134
|
+
@post.update_attributes(:title => "Test2")
|
135
|
+
@post.update_attributes(:title => "Test3")
|
136
|
+
@post.version.should == 2
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should create a history track if changed attributes match tracked attributes" do
|
140
|
+
lambda {
|
141
|
+
@post.update_attributes(:title => "Test2")
|
142
|
+
@post.update_attributes(:title => "Test3")
|
143
|
+
}.should change(HistoryTracker, :count).by(2)
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should create a history track of version 2" do
|
147
|
+
@post.update_attributes(:title => "Test2")
|
148
|
+
@post.update_attributes(:title => "Test3")
|
149
|
+
@post.history_tracks.where(:version => 2).first.should_not be_nil
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should assign modified fields" do
|
153
|
+
@post.update_attributes(:title => "Test2")
|
154
|
+
@post.update_attributes(:title => "Test3")
|
155
|
+
@post.history_tracks.where(:version => 2).first.modified.should == {
|
156
|
+
"title" => "Test3"
|
157
|
+
}
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should assign original fields" do
|
161
|
+
@post.update_attributes(:title => "Test2")
|
162
|
+
@post.update_attributes(:title => "Test3")
|
163
|
+
@post.history_tracks.where(:version => 2).first.original.should == {
|
164
|
+
"title" => "Test2"
|
165
|
+
}
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
it "should assign modifier" do
|
170
|
+
@post.update_attributes(:title => "Another Test", :modifier => @another_user)
|
171
|
+
@post.history_tracks.first.modifier.should == @another_user
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "on update embedded" do
|
176
|
+
it "should assigin version on comment" do
|
177
|
+
@comment.update_attributes(:title => "Test2")
|
178
|
+
@comment.version.should == 2 # first track generated on creation
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should create a history track of version 2" do
|
182
|
+
@comment.update_attributes(:title => "Test2")
|
183
|
+
@comment.history_tracks.where(:version => 2).first.should_not be_nil
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should assign modified fields" do
|
187
|
+
@comment.update_attributes(:title => "Test2")
|
188
|
+
@comment.history_tracks.where(:version => 2).first.modified.should == {
|
189
|
+
"title" => "Test2"
|
190
|
+
}
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should assign original fields" do
|
194
|
+
@comment.update_attributes(:title => "Test2")
|
195
|
+
@comment.history_tracks.where(:version => 2).first.original.should == {
|
196
|
+
"title" => "test"
|
197
|
+
}
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should assign modifier" do
|
201
|
+
@post.update_attributes(:title => "Another Test", :modifier => @another_user)
|
202
|
+
@post.history_tracks.first.modifier.should == @another_user
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe "non-embedded" do
|
207
|
+
it "should undo changes" do
|
208
|
+
@post.update_attributes(:title => "Test2")
|
209
|
+
@post.history_tracks.where(:version => 1).first.undo!
|
210
|
+
@post.reload
|
211
|
+
@post.title.should == "Test"
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should create a new history track after undo" do
|
215
|
+
@post.update_attributes(:title => "Test2")
|
216
|
+
@post.history_tracks.where(:version => 1).first.undo!
|
217
|
+
@post.reload
|
218
|
+
@post.history_tracks.count.should == 2
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should stay the same after undo and redo" do
|
222
|
+
@post.update_attributes(:title => "Test2")
|
223
|
+
@track = @post.history_tracks.where(:version => 1).first
|
224
|
+
@track.undo!
|
225
|
+
@track.redo!
|
226
|
+
@post2 = Post.where(:_id => @post.id).first
|
227
|
+
|
228
|
+
@post.title.should == @post2.title
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "embedded" do
|
233
|
+
it "should undo changes" do
|
234
|
+
@comment.update_attributes(:title => "Test2")
|
235
|
+
@comment.history_tracks.where(:version => 2).first.undo!
|
236
|
+
# reloading an embedded document === KAMIKAZE
|
237
|
+
# at least for the current release of mongoid...
|
238
|
+
@post.reload
|
239
|
+
@comment = @post.comments.first
|
240
|
+
@comment.title.should == "test"
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should create a new history track after undo" do
|
244
|
+
@comment.update_attributes(:title => "Test2")
|
245
|
+
@comment.history_tracks.where(:version => 2).first.undo!
|
246
|
+
@post.reload
|
247
|
+
@comment = @post.comments.first
|
248
|
+
@comment.history_tracks.count.should == 3
|
249
|
+
end
|
250
|
+
|
251
|
+
it "should stay the same after undo and redo" do
|
252
|
+
@comment.update_attributes(:title => "Test2")
|
253
|
+
@track = @comment.history_tracks.where(:version => 2).first
|
254
|
+
@track.undo!
|
255
|
+
@track.redo!
|
256
|
+
@post2 = Post.where(:_id => @post.id).first
|
257
|
+
@comment2 = @post2.comments.first
|
258
|
+
|
259
|
+
@comment.title.should == @comment2.title
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
end
|
264
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
require 'rspec'
|
5
|
+
require 'easy_diff'
|
6
|
+
require 'mongoid'
|
7
|
+
require 'mongoid-history'
|
8
|
+
require 'database_cleaner'
|
9
|
+
|
10
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.before(:suite) do
|
14
|
+
DatabaseCleaner.strategy = :truncation
|
15
|
+
end
|
16
|
+
|
17
|
+
config.after(:each) do
|
18
|
+
DatabaseCleaner.clean
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Mongoid.configure do |config|
|
23
|
+
config.master = Mongo::Connection.new.db("mongoid-history")
|
24
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Mongoid::History::Trackable do
|
4
|
+
before :each do
|
5
|
+
class MyModel
|
6
|
+
include Mongoid::Document
|
7
|
+
include Mongoid::History::Trackable
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
after :each do
|
12
|
+
Mongoid::History.trackable_classes = nil
|
13
|
+
Mongoid::History.trackable_class_options = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should have #track_history" do
|
17
|
+
MyModel.should respond_to :track_history
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should append trackable_classes ONLY when #track_history is called" do
|
21
|
+
Mongoid::History.trackable_classes.should be_blank
|
22
|
+
MyModel.track_history
|
23
|
+
Mongoid::History.trackable_classes.should == [MyModel]
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should append trackable_class_options ONLY when #track_history is called" do
|
27
|
+
Mongoid::History.trackable_class_options.should be_blank
|
28
|
+
MyModel.track_history
|
29
|
+
Mongoid::History.trackable_class_options.keys.should == [:my_model]
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#track_history" do
|
33
|
+
before :each do
|
34
|
+
class MyModel
|
35
|
+
include Mongoid::Document
|
36
|
+
include Mongoid::History::Trackable
|
37
|
+
track_history
|
38
|
+
end
|
39
|
+
|
40
|
+
@expected_option = {
|
41
|
+
:on => :all,
|
42
|
+
:modifier_field => :modifier,
|
43
|
+
:version_field => :version,
|
44
|
+
:scope => :my_model,
|
45
|
+
:except => ["created_at", "updated_at", "version", "modifier_id", "_id", "id"],
|
46
|
+
:track_create => false
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
after :each do
|
51
|
+
Mongoid::History.trackable_classes = nil
|
52
|
+
Mongoid::History.trackable_class_options = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should have default options" do
|
56
|
+
Mongoid::History.trackable_class_options[:my_model].should == @expected_option
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should define callback function #track_update" do
|
60
|
+
MyModel.new.private_methods.collect(&:to_sym).should include(:track_update)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should define callback function #track_create" do
|
64
|
+
MyModel.new.private_methods.collect(&:to_sym).should include(:track_create)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should define #history_trackable_options" do
|
68
|
+
MyModel.history_trackable_options.should == @expected_option
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Mongoid::History::Tracker do
|
4
|
+
before :each do
|
5
|
+
class MyTracker
|
6
|
+
include Mongoid::History::Tracker
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
after :each do
|
11
|
+
Mongoid::History.tracker_class_name = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should set tracker_class_name when included" do
|
15
|
+
Mongoid::History.tracker_class_name.should == :my_tracker
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,245 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mongoid-history
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Aaron Qian
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-03-04 00:00:00 -08:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
type: :runtime
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
name: easy_diff
|
33
|
+
version_requirements: *id001
|
34
|
+
prerelease: false
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
type: :runtime
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ~>
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 15424091
|
43
|
+
segments:
|
44
|
+
- 2
|
45
|
+
- 0
|
46
|
+
- 0
|
47
|
+
- rc
|
48
|
+
- 7
|
49
|
+
version: 2.0.0.rc.7
|
50
|
+
name: mongoid
|
51
|
+
version_requirements: *id002
|
52
|
+
prerelease: false
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
type: :development
|
55
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ~>
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 3
|
61
|
+
segments:
|
62
|
+
- 2
|
63
|
+
- 3
|
64
|
+
- 0
|
65
|
+
version: 2.3.0
|
66
|
+
name: rspec
|
67
|
+
version_requirements: *id003
|
68
|
+
prerelease: false
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
type: :development
|
71
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
hash: 7
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
- 6
|
80
|
+
- 0
|
81
|
+
version: 0.6.0
|
82
|
+
name: yard
|
83
|
+
version_requirements: *id004
|
84
|
+
prerelease: false
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
type: :development
|
87
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ~>
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
hash: 23
|
93
|
+
segments:
|
94
|
+
- 1
|
95
|
+
- 0
|
96
|
+
- 0
|
97
|
+
version: 1.0.0
|
98
|
+
name: bundler
|
99
|
+
version_requirements: *id005
|
100
|
+
prerelease: false
|
101
|
+
- !ruby/object:Gem::Dependency
|
102
|
+
type: :development
|
103
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ~>
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
hash: 7
|
109
|
+
segments:
|
110
|
+
- 1
|
111
|
+
- 5
|
112
|
+
- 2
|
113
|
+
version: 1.5.2
|
114
|
+
name: jeweler
|
115
|
+
version_requirements: *id006
|
116
|
+
prerelease: false
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
type: :development
|
119
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
120
|
+
none: false
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
hash: 3
|
125
|
+
segments:
|
126
|
+
- 0
|
127
|
+
version: "0"
|
128
|
+
name: rcov
|
129
|
+
version_requirements: *id007
|
130
|
+
prerelease: false
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
type: :development
|
133
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ~>
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
hash: 15
|
139
|
+
segments:
|
140
|
+
- 1
|
141
|
+
- 2
|
142
|
+
- 8
|
143
|
+
version: 1.2.8
|
144
|
+
name: reek
|
145
|
+
version_requirements: *id008
|
146
|
+
prerelease: false
|
147
|
+
- !ruby/object:Gem::Dependency
|
148
|
+
type: :development
|
149
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
150
|
+
none: false
|
151
|
+
requirements:
|
152
|
+
- - ~>
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
hash: 11
|
155
|
+
segments:
|
156
|
+
- 2
|
157
|
+
- 1
|
158
|
+
- 0
|
159
|
+
version: 2.1.0
|
160
|
+
name: roodi
|
161
|
+
version_requirements: *id009
|
162
|
+
prerelease: false
|
163
|
+
- !ruby/object:Gem::Dependency
|
164
|
+
type: :development
|
165
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
166
|
+
none: false
|
167
|
+
requirements:
|
168
|
+
- - ">="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
hash: 3
|
171
|
+
segments:
|
172
|
+
- 0
|
173
|
+
version: "0"
|
174
|
+
name: database_cleaner
|
175
|
+
version_requirements: *id010
|
176
|
+
prerelease: false
|
177
|
+
description: |-
|
178
|
+
In frustration of Mongoid::Versioning, I created this plugin for tracking historical changes for any document, including embedded ones. It achieves this by storing all history tracks in a single collection that you define. (See Usage for more details) Embedded documents are referenced by storing an association path, which is an array of document_name and document_id fields starting from the top most parent document and down to the embedded document that should track history.
|
179
|
+
|
180
|
+
This plugin implements multi-user undo, which allows users to undo any history change in any order. Undoing a document also creates a new history track. This is great for auditing and preventing vandalism, but it is probably not suitable for use cases such as a wiki.
|
181
|
+
email: aqian@attinteractive.com
|
182
|
+
executables: []
|
183
|
+
|
184
|
+
extensions: []
|
185
|
+
|
186
|
+
extra_rdoc_files:
|
187
|
+
- LICENSE.txt
|
188
|
+
- README.rdoc
|
189
|
+
files:
|
190
|
+
- .document
|
191
|
+
- .rspec
|
192
|
+
- .rvmrc
|
193
|
+
- Gemfile
|
194
|
+
- LICENSE.txt
|
195
|
+
- README.rdoc
|
196
|
+
- Rakefile
|
197
|
+
- VERSION
|
198
|
+
- lib/mongoid-history.rb
|
199
|
+
- lib/mongoid/history.rb
|
200
|
+
- lib/mongoid/history/trackable.rb
|
201
|
+
- lib/mongoid/history/tracker.rb
|
202
|
+
- mongoid-history.gemspec
|
203
|
+
- spec/integration/integration_spec.rb
|
204
|
+
- spec/spec_helper.rb
|
205
|
+
- spec/trackable_spec.rb
|
206
|
+
- spec/tracker_spec.rb
|
207
|
+
has_rdoc: true
|
208
|
+
homepage: http://github.com/aq1018/mongoid-history
|
209
|
+
licenses:
|
210
|
+
- MIT
|
211
|
+
post_install_message:
|
212
|
+
rdoc_options: []
|
213
|
+
|
214
|
+
require_paths:
|
215
|
+
- lib
|
216
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
217
|
+
none: false
|
218
|
+
requirements:
|
219
|
+
- - ">="
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
hash: 3
|
222
|
+
segments:
|
223
|
+
- 0
|
224
|
+
version: "0"
|
225
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
226
|
+
none: false
|
227
|
+
requirements:
|
228
|
+
- - ">="
|
229
|
+
- !ruby/object:Gem::Version
|
230
|
+
hash: 3
|
231
|
+
segments:
|
232
|
+
- 0
|
233
|
+
version: "0"
|
234
|
+
requirements: []
|
235
|
+
|
236
|
+
rubyforge_project:
|
237
|
+
rubygems_version: 1.5.3
|
238
|
+
signing_key:
|
239
|
+
specification_version: 3
|
240
|
+
summary: history tracking, auditing, undo, redo for mongoid
|
241
|
+
test_files:
|
242
|
+
- spec/integration/integration_spec.rb
|
243
|
+
- spec/spec_helper.rb
|
244
|
+
- spec/trackable_spec.rb
|
245
|
+
- spec/tracker_spec.rb
|