mongoid-history 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +19 -1
- data/Gemfile +1 -2
- data/README.md +123 -1
- data/VERSION +1 -1
- data/lib/mongoid/history.rb +14 -0
- data/lib/mongoid/history/trackable.rb +142 -59
- data/lib/mongoid/history/tracker.rb +77 -27
- data/mongoid-history.gemspec +2 -4
- data/spec/integration/integration_spec.rb +382 -238
- data/spec/integration/multi_relation_spec.rb +9 -2
- data/spec/integration/nested_embedded_documents_spec.rb +7 -5
- data/spec/spec_helper.rb +1 -3
- data/spec/support/mongoid.rb +8 -10
- data/spec/trackable_spec.rb +168 -41
- metadata +3 -5
- data/config/mongoid.yml +0 -8
- data/spec/support/database_cleaner.rb +0 -9
data/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.4.0 (6/12/2013)
|
|
2
|
+
-----------------
|
|
3
|
+
|
|
4
|
+
* Add Mongoid::History.disable and Mongoid::History.enabled? methods for global tracking disablement - [@johnnyshields](https://github.com/johnnyshields)
|
|
5
|
+
* Add `:changes_method` that optionally overrides which method to call to collect changes - [@joelnordel](https://github.com/joelnordell).
|
|
6
|
+
* [API Change] The `:destroy` action now stores trackers in the format `original=value, modified=nil` (previously it was the reverse) - [@johnnyshields](https://github.com/johnnyshields)
|
|
7
|
+
* Support for polymorphic embedded classes - [@tstepp](https://github.com/tstepp)
|
|
8
|
+
* Support for Mongoid field aliases, e.g. `field :n, as: :name` - [@johnnyshields](https://github.com/johnnyshields)
|
|
9
|
+
* Support for Mongoid embedded aliases, e.g. `embeds_many :comments, store_as: :coms` - [@johnnyshields](https://github.com/johnnyshields)
|
|
10
|
+
* Add `#tracked_changes` and `#tracked_edits` methods to `Tracker` class for nicer change summaries - [@johnnyshields](https://github.com/johnnyshields) and [@tstepp](https://github.com/tstepp)
|
|
11
|
+
* Refactored and exposed `#trackable_parent_class` in `Tracker`, which returns the class of the trackable regardless of whether the trackable itself has been destroyed - [@johnnyshields](https://github.com/johnnyshields)
|
|
12
|
+
* Add class-level `#tracked_field?` and `#tracked_fields` methods; refactor logic to determine whether a field is tracked - [@johnnyshields](https://github.com/johnnyshields)
|
|
13
|
+
* Fix bug in Trackable#track_update where `return` condition at beginning of method caused a short-circuit where memoization would not be cleared properly. - [@johnnyshields](https://github.com/johnnyshields)
|
|
14
|
+
* Tests: Added spec for nested embedded documents - [@matekb](https://github.com/matekb)
|
|
15
|
+
* Tests: Test run time cut in half (~2.5s versus ~5s) by using `#let` helper and removing class initialization before each test - [@johnnyshields](https://github.com/johnnyshields)
|
|
16
|
+
* Tests: Remove `database_cleaner` gem in favor of `Mongoid.purge!` - [@johnnyshields](https://github.com/johnnyshields)
|
|
17
|
+
* Tests: Remove dependency on non-committed file `mongoid.yml` and hardcode collection to `mongoid_history_test` - [@johnnyshields](https://github.com/johnnyshields)
|
|
18
|
+
|
|
19
|
+
0.3.3 (4/1/2013)
|
|
2
20
|
----------------
|
|
3
21
|
|
|
4
22
|
* [#42](https://github.com/aq1018/mongoid-history/issues/42) Fix: corrected creation of association chain when using nested embedded documents - [@matekb](https://github.com/matekb).
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -2,6 +2,7 @@ mongoid-history
|
|
|
2
2
|
===============
|
|
3
3
|
|
|
4
4
|
[](http://travis-ci.org/aq1018/mongoid-history)
|
|
5
|
+
[](https://codeclimate.com/github/aq1018/mongoid-history)
|
|
5
6
|
|
|
6
7
|
Mongoid-history tracks historical changes for any document, including embedded ones. It achieves this by storing all history tracks in a single collection that you define. 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.
|
|
7
8
|
|
|
@@ -10,7 +11,7 @@ This gem also implements multi-user undo, which allows users to undo any history
|
|
|
10
11
|
Stable Release
|
|
11
12
|
--------------
|
|
12
13
|
|
|
13
|
-
You're reading the documentation the 0.
|
|
14
|
+
You're reading the documentation the 0.4.x release that supports Mongoid 3.x. For 2.x compatible mongoid-history, please use a 0.2.x version from the [2.x-stable branch](https://github.com/aq1018/mongoid-history/tree/2.4-stable).
|
|
14
15
|
|
|
15
16
|
Install
|
|
16
17
|
-------
|
|
@@ -160,7 +161,128 @@ post.undo! user
|
|
|
160
161
|
Comment.disable_tracking do
|
|
161
162
|
comment.update_attributes(:title => "Test 3")
|
|
162
163
|
end
|
|
164
|
+
|
|
165
|
+
# globally disable all history tracking
|
|
166
|
+
Mongoid::History.disable do
|
|
167
|
+
comment.update_attributes(:title => "Test 3")
|
|
168
|
+
user.update_attributes(:name => "Eddie Van Halen")
|
|
169
|
+
end
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Retrieving the list of tracked fields**
|
|
173
|
+
|
|
174
|
+
```ruby
|
|
175
|
+
class Book
|
|
176
|
+
...
|
|
177
|
+
field :title
|
|
178
|
+
field :author
|
|
179
|
+
field :price
|
|
180
|
+
track_history :on => [:title, :price]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
Book.tracked_fields #=> ["title", "price"]
|
|
184
|
+
Book.tracked_field?(:title) #=> true
|
|
185
|
+
Book.tracked_field?(:author) #=> false
|
|
163
186
|
```
|
|
187
|
+
|
|
188
|
+
**Displaying history trackers as an audit trail**
|
|
189
|
+
|
|
190
|
+
In your Controller:
|
|
191
|
+
|
|
192
|
+
```ruby
|
|
193
|
+
# Fetch history trackers
|
|
194
|
+
@trackers = HistoryTracker.limit(25)
|
|
195
|
+
|
|
196
|
+
# get change set for the first tracker
|
|
197
|
+
@changes = @trackers.first.tracked_changes
|
|
198
|
+
#=> {field: {to: val1, from: val2}}
|
|
199
|
+
|
|
200
|
+
# get edit set for the first tracker
|
|
201
|
+
@edits = @trackers.first.tracked_changes
|
|
202
|
+
#=> { add: {field: val},
|
|
203
|
+
# remove: {field: val},
|
|
204
|
+
# modify: { to: val1, from: val2 },
|
|
205
|
+
# array: { add: [val2], remove: [val1] } }
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
In your View, you might do something like (example in HAML format):
|
|
209
|
+
|
|
210
|
+
```haml
|
|
211
|
+
%ul.changes
|
|
212
|
+
- (@edits[:add]||[]).each do |k,v|
|
|
213
|
+
%li.remove Added field #{k} value #{v}
|
|
214
|
+
|
|
215
|
+
- (@edits[:modify]||[]).each do |k,v|
|
|
216
|
+
%li.modify Changed field #{k} from #{v[:from]} to #{v[:to]}
|
|
217
|
+
|
|
218
|
+
- (@edits[:array]||[]).each do |k,v|
|
|
219
|
+
%li.modify
|
|
220
|
+
- if v[:remove].nil?
|
|
221
|
+
Changed field #{k} by adding #{v[:add]}
|
|
222
|
+
- elsif v[:add].nil?
|
|
223
|
+
Changed field #{k} by removing #{v[:remove]}
|
|
224
|
+
- else
|
|
225
|
+
Changed field #{k} by adding #{v[:add]} and removing #{v[:remove]}
|
|
226
|
+
|
|
227
|
+
- (@edits[:remove]||[]).each do |k,v|
|
|
228
|
+
%li.remove Removed field #{k} (was previously #{v})
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Using an alternate changes method**
|
|
232
|
+
|
|
233
|
+
Sometimes you may wish to provide an alternate method for determining which changes should be tracked. For example, if you are using embedded documents
|
|
234
|
+
and nested attributes, you may wish to write your own changes method that includes changes from the embedded documents.
|
|
235
|
+
|
|
236
|
+
Mongoid::History provides an option named `:changes_method` which allows you to do this. It defaults to `:changes`, which is the standard changes method.
|
|
237
|
+
|
|
238
|
+
Example:
|
|
239
|
+
|
|
240
|
+
```ruby
|
|
241
|
+
class Foo
|
|
242
|
+
include Mongoid::Document
|
|
243
|
+
include Mongoid::Timestamps
|
|
244
|
+
include Mongoid::History::Trackable
|
|
245
|
+
|
|
246
|
+
field :bar
|
|
247
|
+
embeds_one :baz
|
|
248
|
+
accepts_nested_attributes_for :baz
|
|
249
|
+
|
|
250
|
+
# use changes_with_baz to include baz's changes in this document's
|
|
251
|
+
# history.
|
|
252
|
+
track_history :changes_method => :changes_with_baz
|
|
253
|
+
|
|
254
|
+
def changes_with_baz
|
|
255
|
+
if baz.changed?
|
|
256
|
+
changes.merge( :baz => summarized_changes(baz) )
|
|
257
|
+
else
|
|
258
|
+
changes
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
private
|
|
263
|
+
# This method takes the changes from an embedded doc and formats them
|
|
264
|
+
# in a summarized way, similar to how the embedded doc appears in the
|
|
265
|
+
# parent document's attributes
|
|
266
|
+
def summarized_changes obj
|
|
267
|
+
obj.changes.keys.map do |field|
|
|
268
|
+
next unless obj.respond_to?("#{field}_change")
|
|
269
|
+
[ { field => obj.send("#{field}_change")[0] },
|
|
270
|
+
{ field => obj.send("#{field}_change")[1] } ]
|
|
271
|
+
end.compact.transpose.map do |fields|
|
|
272
|
+
fields.inject({}) {|map,f| map.merge(f)}
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
class Baz
|
|
278
|
+
include Mongoid::Document
|
|
279
|
+
include Mongoid::Timestamps
|
|
280
|
+
|
|
281
|
+
embedded_in :foo
|
|
282
|
+
field :value
|
|
283
|
+
end
|
|
284
|
+
```
|
|
285
|
+
|
|
164
286
|
For more examples, check out [spec/integration/integration_spec.rb](https://github.com/aq1018/mongoid-history/blob/master/spec/integration/integration_spec.rb).
|
|
165
287
|
|
|
166
288
|
Contributing to mongoid-history
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.4.0
|
data/lib/mongoid/history.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
module Mongoid
|
|
2
2
|
module History
|
|
3
|
+
GLOBAL_TRACK_HISTORY_FLAG = "mongoid_history_trackable_enabled"
|
|
4
|
+
|
|
3
5
|
mattr_accessor :tracker_class_name
|
|
4
6
|
mattr_accessor :trackable_class_options
|
|
5
7
|
mattr_accessor :modifier_class_name
|
|
@@ -9,5 +11,17 @@ module Mongoid
|
|
|
9
11
|
@tracker_class ||= tracker_class_name.to_s.classify.constantize
|
|
10
12
|
end
|
|
11
13
|
|
|
14
|
+
def self.disable(&block)
|
|
15
|
+
begin
|
|
16
|
+
Thread.current[GLOBAL_TRACK_HISTORY_FLAG] = false
|
|
17
|
+
yield
|
|
18
|
+
ensure
|
|
19
|
+
Thread.current[GLOBAL_TRACK_HISTORY_FLAG] = true
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.enabled?
|
|
24
|
+
Thread.current[GLOBAL_TRACK_HISTORY_FLAG] != false
|
|
25
|
+
end
|
|
12
26
|
end
|
|
13
27
|
end
|
|
@@ -10,6 +10,7 @@ module Mongoid::History
|
|
|
10
10
|
:except => [:created_at, :updated_at],
|
|
11
11
|
:modifier_field => :modifier,
|
|
12
12
|
:version_field => :version,
|
|
13
|
+
:changes_method => :changes,
|
|
13
14
|
:scope => scope_name,
|
|
14
15
|
:track_create => false,
|
|
15
16
|
:track_update => true,
|
|
@@ -18,19 +19,14 @@ module Mongoid::History
|
|
|
18
19
|
|
|
19
20
|
options = default_options.merge(options)
|
|
20
21
|
|
|
21
|
-
# normalize except fields
|
|
22
|
-
# manually ensure _id, id, version will not be tracked in history
|
|
22
|
+
# normalize :except fields to an array of database field strings
|
|
23
23
|
options[:except] = [options[:except]] unless options[:except].is_a? Array
|
|
24
|
-
options[:except]
|
|
25
|
-
options[:except] << "#{options[:modifier_field]}_id".to_sym
|
|
26
|
-
options[:except] += [:_id, :id]
|
|
27
|
-
options[:except] = options[:except].map(&:to_s).flatten.compact.uniq
|
|
28
|
-
options[:except].map(&:to_s)
|
|
24
|
+
options[:except] = options[:except].map{|field| database_field_name(field)}.compact.uniq
|
|
29
25
|
|
|
30
|
-
# normalize fields to
|
|
26
|
+
# normalize :on fields to either :all or an array of database field strings
|
|
31
27
|
if options[:on] != :all
|
|
32
28
|
options[:on] = [options[:on]] unless options[:on].is_a? Array
|
|
33
|
-
options[:on] = options[:on].map(
|
|
29
|
+
options[:on] = options[:on].map{|field| database_field_name(field)}.compact.uniq
|
|
34
30
|
end
|
|
35
31
|
|
|
36
32
|
field options[:version_field].to_sym, :type => Integer
|
|
@@ -54,8 +50,7 @@ module Mongoid::History
|
|
|
54
50
|
end
|
|
55
51
|
|
|
56
52
|
def track_history?
|
|
57
|
-
enabled
|
|
58
|
-
enabled.nil? ? true : enabled
|
|
53
|
+
Mongoid::History.enabled? && Thread.current[track_history_flag] != false
|
|
59
54
|
end
|
|
60
55
|
|
|
61
56
|
def disable_tracking(&block)
|
|
@@ -101,6 +96,14 @@ module Mongoid::History
|
|
|
101
96
|
save!
|
|
102
97
|
end
|
|
103
98
|
|
|
99
|
+
def get_embedded(name)
|
|
100
|
+
self.send(self.class.embedded_alias(name))
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def create_embedded(name, value)
|
|
104
|
+
self.send("create_#{self.class.embedded_alias(name)}!", value)
|
|
105
|
+
end
|
|
106
|
+
|
|
104
107
|
private
|
|
105
108
|
def get_versions_criteria(options_or_version)
|
|
106
109
|
if options_or_version.is_a? Hash
|
|
@@ -124,10 +127,6 @@ module Mongoid::History
|
|
|
124
127
|
versions.desc(:version)
|
|
125
128
|
end
|
|
126
129
|
|
|
127
|
-
def should_track_update?
|
|
128
|
-
track_history? && !modified_attributes_for_update.blank?
|
|
129
|
-
end
|
|
130
|
-
|
|
131
130
|
def traverse_association_chain(node=self)
|
|
132
131
|
list = node._parent ? traverse_association_chain(node._parent) : []
|
|
133
132
|
list << association_hash(node)
|
|
@@ -141,7 +140,7 @@ module Mongoid::History
|
|
|
141
140
|
# the child to parent (embedded_in, belongs_to) relation will be defined
|
|
142
141
|
if node._parent
|
|
143
142
|
meta = node._parent.relations.values.select do |relation|
|
|
144
|
-
relation.class_name == node.
|
|
143
|
+
relation.class_name == node.metadata.class_name.to_s
|
|
145
144
|
end.first
|
|
146
145
|
end
|
|
147
146
|
|
|
@@ -151,81 +150,68 @@ module Mongoid::History
|
|
|
151
150
|
ActiveSupport::OrderedHash['name', name, 'id', node.id]
|
|
152
151
|
end
|
|
153
152
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
153
|
+
# Returns a Hash of field name to pairs of original and modified values
|
|
154
|
+
# for each tracked field for a given action.
|
|
155
|
+
#
|
|
156
|
+
# @param [ String | Symbol ] action The modification action (:create, :update, :destroy)
|
|
157
|
+
#
|
|
158
|
+
# @return [ Hash<String, Array<Object>> ] the pairs of original and modified
|
|
159
|
+
# values for each field
|
|
160
|
+
def modified_attributes_for_action(action)
|
|
161
|
+
case action.to_sym
|
|
162
|
+
when :destroy then modified_attributes_for_destroy
|
|
163
|
+
when :create then modified_attributes_for_create
|
|
164
|
+
else modified_attributes_for_update
|
|
164
165
|
end
|
|
165
166
|
end
|
|
166
167
|
|
|
168
|
+
def modified_attributes_for_update
|
|
169
|
+
@modified_attributes_for_update ||= self.send(history_trackable_options[:changes_method]).select{|k, v| self.class.tracked_field?(k, :update)}
|
|
170
|
+
end
|
|
171
|
+
|
|
167
172
|
def modified_attributes_for_create
|
|
168
|
-
@modified_attributes_for_create ||= attributes.inject({}) do |h,
|
|
169
|
-
k,v = pair
|
|
173
|
+
@modified_attributes_for_create ||= attributes.inject({}) do |h,(k,v)|
|
|
170
174
|
h[k] = [nil, v]
|
|
171
175
|
h
|
|
172
|
-
end.
|
|
173
|
-
history_trackable_options[:except].include?(k)
|
|
174
|
-
end
|
|
176
|
+
end.select{|k, v| self.class.tracked_field?(k, :create)}
|
|
175
177
|
end
|
|
176
178
|
|
|
177
179
|
def modified_attributes_for_destroy
|
|
178
|
-
@modified_attributes_for_destroy ||= attributes.inject({}) do |h,
|
|
179
|
-
k,
|
|
180
|
-
h[k] = [nil, v]
|
|
180
|
+
@modified_attributes_for_destroy ||= attributes.inject({}) do |h,(k,v)|
|
|
181
|
+
h[k] = [v, nil]
|
|
181
182
|
h
|
|
182
|
-
end
|
|
183
|
+
end.select{|k, v| self.class.tracked_field?(k, :destroy)}
|
|
183
184
|
end
|
|
184
185
|
|
|
185
|
-
def history_tracker_attributes(
|
|
186
|
+
def history_tracker_attributes(action)
|
|
186
187
|
return @history_tracker_attributes if @history_tracker_attributes
|
|
187
188
|
|
|
188
189
|
@history_tracker_attributes = {
|
|
189
190
|
:association_chain => traverse_association_chain,
|
|
190
191
|
:scope => history_trackable_options[:scope],
|
|
191
|
-
:modifier
|
|
192
|
+
:modifier => send(history_trackable_options[:modifier_field])
|
|
192
193
|
}
|
|
193
194
|
|
|
194
|
-
original, modified = transform_changes(
|
|
195
|
-
when :destroy then modified_attributes_for_destroy
|
|
196
|
-
when :create then modified_attributes_for_create
|
|
197
|
-
else modified_attributes_for_update
|
|
198
|
-
end)
|
|
195
|
+
original, modified = transform_changes(modified_attributes_for_action(action))
|
|
199
196
|
|
|
200
197
|
@history_tracker_attributes[:original] = original
|
|
201
198
|
@history_tracker_attributes[:modified] = modified
|
|
202
199
|
@history_tracker_attributes
|
|
203
200
|
end
|
|
204
201
|
|
|
205
|
-
def
|
|
206
|
-
|
|
207
|
-
current_version = (self.send(history_trackable_options[:version_field]) || 0 ) + 1
|
|
208
|
-
self.send("#{history_trackable_options[:version_field]}=", current_version)
|
|
209
|
-
Mongoid::History.tracker_class.create!(history_tracker_attributes(:update).merge(:version => current_version, :action => "update", :trackable => self))
|
|
210
|
-
clear_memoization
|
|
202
|
+
def track_create
|
|
203
|
+
track_history_for_action(:create)
|
|
211
204
|
end
|
|
212
205
|
|
|
213
|
-
def
|
|
214
|
-
|
|
215
|
-
current_version = (self.send(history_trackable_options[:version_field]) || 0 ) + 1
|
|
216
|
-
self.send("#{history_trackable_options[:version_field]}=", current_version)
|
|
217
|
-
Mongoid::History.tracker_class.create!(history_tracker_attributes(:create).merge(:version => current_version, :action => "create", :trackable => self))
|
|
218
|
-
clear_memoization
|
|
206
|
+
def track_update
|
|
207
|
+
track_history_for_action(:update)
|
|
219
208
|
end
|
|
220
209
|
|
|
221
210
|
def track_destroy
|
|
222
|
-
|
|
223
|
-
current_version = (self.send(history_trackable_options[:version_field]) || 0 ) + 1
|
|
224
|
-
Mongoid::History.tracker_class.create!(history_tracker_attributes(:destroy).merge(:version => current_version, :action => "destroy", :trackable => self))
|
|
225
|
-
clear_memoization
|
|
211
|
+
track_history_for_action(:destroy)
|
|
226
212
|
end
|
|
227
213
|
|
|
228
|
-
def
|
|
214
|
+
def clear_trackable_memoization
|
|
229
215
|
@history_tracker_attributes = nil
|
|
230
216
|
@modified_attributes_for_create = nil
|
|
231
217
|
@modified_attributes_for_update = nil
|
|
@@ -244,12 +230,109 @@ module Mongoid::History
|
|
|
244
230
|
[ original, modified ]
|
|
245
231
|
end
|
|
246
232
|
|
|
233
|
+
protected
|
|
234
|
+
|
|
235
|
+
def track_history_for_action?(action)
|
|
236
|
+
track_history? && !(action.to_sym == :update && modified_attributes_for_update.blank?)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def track_history_for_action(action)
|
|
240
|
+
if track_history_for_action?(action)
|
|
241
|
+
current_version = (self.send(history_trackable_options[:version_field]) || 0 ) + 1
|
|
242
|
+
self.send("#{history_trackable_options[:version_field]}=", current_version)
|
|
243
|
+
Mongoid::History.tracker_class.create!(history_tracker_attributes(action.to_sym).merge(version: current_version, action: action.to_s, trackable: self))
|
|
244
|
+
end
|
|
245
|
+
clear_trackable_memoization
|
|
246
|
+
end
|
|
247
247
|
end
|
|
248
248
|
|
|
249
249
|
module SingletonMethods
|
|
250
|
+
|
|
251
|
+
# Whether or not the field should be tracked.
|
|
252
|
+
#
|
|
253
|
+
# @param [ String | Symbol ] field The name or alias of the field
|
|
254
|
+
# @param [ String | Symbol ] action The optional action name (:create, :update, or :destroy)
|
|
255
|
+
#
|
|
256
|
+
# @return [ Boolean ] whether or not the field is tracked for the given action
|
|
257
|
+
def tracked_field?(field, action = :update)
|
|
258
|
+
tracked_fields_for_action(action).include? database_field_name(field)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Retrieves the list of tracked fields for a given action.
|
|
262
|
+
#
|
|
263
|
+
# @param [ String | Symbol ] action The action name (:create, :update, or :destroy)
|
|
264
|
+
#
|
|
265
|
+
# @return [ Array < String > ] the list of tracked fields for the given action
|
|
266
|
+
def tracked_fields_for_action(action)
|
|
267
|
+
case action.to_sym
|
|
268
|
+
when :destroy then tracked_fields + reserved_tracked_fields
|
|
269
|
+
else tracked_fields
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Retrieves the memoized base list of tracked fields, excluding reserved fields.
|
|
274
|
+
#
|
|
275
|
+
# @return [ Array < String > ] the base list of tracked database field names
|
|
276
|
+
def tracked_fields
|
|
277
|
+
@tracked_fields ||= self.fields.keys.select do |field|
|
|
278
|
+
h = history_trackable_options
|
|
279
|
+
(h[:on]==:all || h[:on].include?(field)) && !h[:except].include?(field)
|
|
280
|
+
end - reserved_tracked_fields
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Retrieves the memoized list of reserved tracked fields, which are only included for certain actions.
|
|
284
|
+
#
|
|
285
|
+
# @return [ Array < String > ] the list of reserved database field names
|
|
286
|
+
def reserved_tracked_fields
|
|
287
|
+
@reserved_tracked_fields ||= ["_id", history_trackable_options[:version_field].to_s, "#{history_trackable_options[:modifier_field]}_id"]
|
|
288
|
+
end
|
|
289
|
+
|
|
250
290
|
def history_trackable_options
|
|
251
291
|
@history_trackable_options ||= Mongoid::History.trackable_class_options[self.collection_name.to_s.singularize.to_sym]
|
|
252
292
|
end
|
|
293
|
+
|
|
294
|
+
# Indicates whether there is an Embedded::One relation for the given embedded field.
|
|
295
|
+
#
|
|
296
|
+
# @param [ String | Symbol ] embed The name of the embedded field
|
|
297
|
+
#
|
|
298
|
+
# @return [ Boolean ] true if there is an Embedded::One relation for the given embedded field
|
|
299
|
+
def embeds_one?(embed)
|
|
300
|
+
relation_of(embed) == Mongoid::Relations::Embedded::One
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Indicates whether there is an Embedded::Many relation for the given embedded field.
|
|
304
|
+
#
|
|
305
|
+
# @param [ String | Symbol ] embed The name of the embedded field
|
|
306
|
+
#
|
|
307
|
+
# @return [ Boolean ] true if there is an Embedded::Many relation for the given embedded field
|
|
308
|
+
def embeds_many?(embed)
|
|
309
|
+
relation_of(embed) == Mongoid::Relations::Embedded::Many
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Retrieves the database representation of an embedded field name, in case the :store_as option is used.
|
|
313
|
+
#
|
|
314
|
+
# @param [ String | Symbol ] embed The name or alias of the embedded field
|
|
315
|
+
#
|
|
316
|
+
# @return [ String ] the database name of the embedded field
|
|
317
|
+
def embedded_alias(embed)
|
|
318
|
+
embedded_aliases[embed]
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
protected
|
|
322
|
+
|
|
323
|
+
# Retrieves the memoized hash of embedded aliases and their associated database representations.
|
|
324
|
+
#
|
|
325
|
+
# @return [ Hash < String, String > ] hash of embedded aliases (keys) to database representations (values)
|
|
326
|
+
def embedded_aliases
|
|
327
|
+
@embedded_aliases ||= relations.inject(HashWithIndifferentAccess.new) do |h,(k,v)|
|
|
328
|
+
h[v[:store_as]||k]=k; h
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def relation_of(embed)
|
|
333
|
+
meta = reflect_on_association(embedded_alias(embed))
|
|
334
|
+
meta ? meta.relation : nil
|
|
335
|
+
end
|
|
253
336
|
end
|
|
254
337
|
end
|
|
255
338
|
end
|