mongo_mapper_acts_as_versioned 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +5 -1
- data/lib/acts_as_versioned.rb +150 -146
- data/lib/acts_as_versioned/version.rb +6 -2
- data/spec/acts_as_versioned_spec.rb +2 -2
- metadata +2 -2
data/README.md
CHANGED
@@ -9,7 +9,7 @@ Basic MongoMapper port of technoweenie's [acts_as_versioned](http://github.com/t
|
|
9
9
|
class Page
|
10
10
|
include MongoMapper::Document
|
11
11
|
|
12
|
-
plugin
|
12
|
+
plugin MongoMapper::Acts::Versioned
|
13
13
|
|
14
14
|
key :title, String
|
15
15
|
end
|
@@ -60,6 +60,10 @@ Simply add `self.skipped_keys << 'new_skipped_key'` somewhere in your model.
|
|
60
60
|
* Properly document those options
|
61
61
|
* Support SCI
|
62
62
|
|
63
|
+
## Bundler note
|
64
|
+
|
65
|
+
Make sure to specify `:require => 'acts_as_versioned'` in your Gemfile.
|
66
|
+
|
63
67
|
## Copyright
|
64
68
|
|
65
69
|
Copyright (c) 2010 Gigamo <gigamo@gmail.com>. See LICENSE for details.
|
data/lib/acts_as_versioned.rb
CHANGED
@@ -1,178 +1,182 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
module MongoMapper
|
2
|
+
module Acts
|
3
|
+
module Versioned
|
4
|
+
CALLBACKS = [:set_new_version, :save_version, :save_version?]
|
5
|
+
|
6
|
+
def self.configure(model)
|
7
|
+
model.class_eval do
|
8
|
+
const_set(:Version, Class.new).class_eval do
|
9
|
+
include MongoMapper::Document
|
10
|
+
|
11
|
+
key :version, Integer
|
12
|
+
key :changed_attributes, Hash
|
13
|
+
|
14
|
+
def self.before(version)
|
15
|
+
where(
|
16
|
+
super_foreign_key => version[super_foreign_key],
|
17
|
+
:version.lt => version.version
|
18
|
+
).sort(:version.desc).first
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.after(version)
|
22
|
+
where(
|
23
|
+
super_foreign_key => version[super_foreign_key],
|
24
|
+
:version.gt => version.version
|
25
|
+
).sort(:version.asc).first
|
26
|
+
end
|
27
|
+
|
28
|
+
def previous
|
29
|
+
self.class.before(self)
|
30
|
+
end
|
31
|
+
|
32
|
+
def next
|
33
|
+
self.class.after(self)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.super_foreign_key
|
37
|
+
original_class.to_s.foreign_key
|
38
|
+
end
|
39
|
+
|
40
|
+
class << self
|
41
|
+
protected :super_foreign_key
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
versioned_class.cattr_accessor :original_class
|
46
|
+
versioned_class.original_class = self
|
47
|
+
versioned_class.set_collection_name "#{self.collection_name.singularize}_versions"
|
48
|
+
versioned_class.belongs_to self.to_s.demodulize.underscore.to_sym,
|
49
|
+
:class_name => "::#{self}",
|
50
|
+
:foreign_key => self.to_s.foreign_key
|
51
|
+
end
|
8
52
|
|
9
|
-
key :version,
|
10
|
-
|
53
|
+
model.key :version, Integer
|
54
|
+
model.many :versions, :class_name => "#{model}::Version",
|
55
|
+
:foreign_key => model.to_s.foreign_key, :dependent => :destroy do
|
56
|
+
def earliest
|
57
|
+
query.sort(:version).first
|
58
|
+
end
|
11
59
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
:version.lt => version.version
|
16
|
-
).sort(:version.desc).first
|
60
|
+
def latest
|
61
|
+
query.sort(:version.desc).first
|
62
|
+
end
|
17
63
|
end
|
64
|
+
model.before_save :set_new_version
|
65
|
+
model.after_save :save_version
|
66
|
+
end
|
18
67
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
68
|
+
module InstanceMethods
|
69
|
+
def save_version
|
70
|
+
if @saving_version
|
71
|
+
@saving_version = nil
|
72
|
+
|
73
|
+
rev = self.class.versioned_class.new
|
74
|
+
clone_versioned_model(self, rev)
|
75
|
+
rev.version = version
|
76
|
+
rev[self.class.to_s.foreign_key] = id
|
77
|
+
rev.save!
|
78
|
+
end
|
24
79
|
end
|
25
80
|
|
26
|
-
def
|
27
|
-
self.class.
|
28
|
-
|
81
|
+
def revert_to(version)
|
82
|
+
if version.is_a?(self.class.versioned_class)
|
83
|
+
return false unless version[self.class.to_s.foreign_key] == id and !version.new_record?
|
84
|
+
else
|
85
|
+
return false unless version = versions.where(:version => version).first
|
86
|
+
end
|
29
87
|
|
30
|
-
|
31
|
-
self.
|
32
|
-
end
|
88
|
+
clone_versioned_model(version, self)
|
89
|
+
self.version = version.version
|
33
90
|
|
34
|
-
|
35
|
-
original_class.to_s.foreign_key
|
91
|
+
true
|
36
92
|
end
|
37
93
|
|
38
|
-
|
39
|
-
|
94
|
+
def revert_to!(version)
|
95
|
+
revert_to(version) ? save_without_revision : false
|
40
96
|
end
|
41
|
-
end
|
42
|
-
|
43
|
-
versioned_class.cattr_accessor :original_class
|
44
|
-
versioned_class.original_class = self
|
45
|
-
versioned_class.set_collection_name "#{self.collection_name.singularize}_versions"
|
46
|
-
versioned_class.belongs_to self.to_s.demodulize.underscore.to_sym,
|
47
|
-
:class_name => "::#{self}",
|
48
|
-
:foreign_key => self.to_s.foreign_key
|
49
|
-
end
|
50
|
-
|
51
|
-
model.key :version, Integer
|
52
|
-
model.many :versions, :class_name => "#{model}::Version",
|
53
|
-
:foreign_key => model.to_s.foreign_key, :dependent => :destroy do
|
54
|
-
def earliest
|
55
|
-
query.sort(:version).first
|
56
|
-
end
|
57
|
-
|
58
|
-
def latest
|
59
|
-
query.sort(:version.desc).first
|
60
|
-
end
|
61
|
-
end
|
62
|
-
model.before_save :set_new_version
|
63
|
-
model.after_save :save_version
|
64
|
-
end
|
65
97
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
98
|
+
def save_without_revision
|
99
|
+
save_without_revision!
|
100
|
+
true
|
101
|
+
rescue
|
102
|
+
false
|
103
|
+
end
|
70
104
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
77
|
-
end
|
105
|
+
def save_without_revision!
|
106
|
+
without_revision do
|
107
|
+
save!
|
108
|
+
end
|
109
|
+
end
|
78
110
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
return false unless version = versions.where(:version => version).first
|
84
|
-
end
|
111
|
+
def clone_versioned_model(orig_model, new_model)
|
112
|
+
if orig_model.is_a?(self.class.versioned_class)
|
113
|
+
orig_model = orig_model.changed_attributes
|
114
|
+
end
|
85
115
|
|
86
|
-
|
87
|
-
|
116
|
+
if new_model.is_a?(self.class.versioned_class)
|
117
|
+
new_model = new_model.changed_attributes
|
118
|
+
end
|
88
119
|
|
89
|
-
|
90
|
-
|
120
|
+
self.class.versioned_keys.each do |col|
|
121
|
+
new_model[col] = orig_model[col]
|
122
|
+
end
|
123
|
+
end
|
91
124
|
|
92
|
-
|
93
|
-
|
94
|
-
|
125
|
+
def save_version?
|
126
|
+
(self.class.versioned_keys & changed).any?
|
127
|
+
end
|
95
128
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
rescue
|
100
|
-
false
|
101
|
-
end
|
129
|
+
def without_revision(&block)
|
130
|
+
self.class.without_revision(&block)
|
131
|
+
end
|
102
132
|
|
103
|
-
|
104
|
-
|
105
|
-
save!
|
106
|
-
end
|
107
|
-
end
|
133
|
+
def empty_callback
|
134
|
+
end
|
108
135
|
|
109
|
-
|
110
|
-
if orig_model.is_a?(self.class.versioned_class)
|
111
|
-
orig_model = orig_model.changed_attributes
|
112
|
-
end
|
136
|
+
protected
|
113
137
|
|
114
|
-
|
115
|
-
|
116
|
-
|
138
|
+
def set_new_version
|
139
|
+
@saving_version = new_record? || save_version?
|
140
|
+
self.version = next_version if @saving_version
|
141
|
+
end
|
117
142
|
|
118
|
-
|
119
|
-
|
143
|
+
def next_version
|
144
|
+
(new_record? ? 0 : versions.map(&:version).max) + 1
|
145
|
+
end
|
120
146
|
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def save_version?
|
124
|
-
(self.class.versioned_keys & changed).any?
|
125
|
-
end
|
126
|
-
|
127
|
-
def without_revision(&block)
|
128
|
-
self.class.without_revision(&block)
|
129
|
-
end
|
130
|
-
|
131
|
-
def empty_callback
|
132
|
-
end
|
133
|
-
|
134
|
-
protected
|
135
147
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
def next_version
|
142
|
-
(new_record? ? 0 : versions.map(&:version).max) + 1
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
module ClassMethods
|
147
|
-
def versioned_class
|
148
|
-
const_get(:Version)
|
149
|
-
end
|
148
|
+
module ClassMethods
|
149
|
+
def versioned_class
|
150
|
+
const_get(:Version)
|
151
|
+
end
|
150
152
|
|
151
|
-
|
152
|
-
|
153
|
-
|
153
|
+
def versioned_keys
|
154
|
+
keys.keys - skipped_keys
|
155
|
+
end
|
154
156
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
157
|
+
def without_revision
|
158
|
+
class_eval do
|
159
|
+
CALLBACKS.each do |attr_name|
|
160
|
+
alias_method :"orig_#{attr_name}", attr_name
|
161
|
+
alias_method attr_name, :empty_callback
|
162
|
+
end
|
163
|
+
end
|
164
|
+
yield
|
165
|
+
ensure
|
166
|
+
class_eval do
|
167
|
+
CALLBACKS.each do |attr_name|
|
168
|
+
alias_method attr_name, :"orig_#{attr_name}"
|
169
|
+
end
|
170
|
+
end
|
160
171
|
end
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
172
|
+
|
173
|
+
def skipped_keys
|
174
|
+
@skipped_keys ||= [
|
175
|
+
'_id', 'created_at', 'updated_at', 'creator_id',
|
176
|
+
'updater_id', 'version', self.class.to_s.foreign_key
|
177
|
+
]
|
167
178
|
end
|
168
179
|
end
|
169
180
|
end
|
170
|
-
|
171
|
-
def skipped_keys
|
172
|
-
@skipped_keys ||= [
|
173
|
-
'_id', 'created_at', 'updated_at', 'creator_id',
|
174
|
-
'updater_id', 'version', self.class.to_s.foreign_key
|
175
|
-
]
|
176
|
-
end
|
177
181
|
end
|
178
182
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe MongoMapper::Acts::Versioned do
|
4
4
|
before :all do
|
5
5
|
class Landmark
|
6
6
|
include MongoMapper::Document
|
7
7
|
|
8
|
-
plugin
|
8
|
+
plugin MongoMapper::Acts::Versioned
|
9
9
|
|
10
10
|
self.skipped_keys << 'depth'
|
11
11
|
|