Skip to content

Commit

Permalink
allow modifier field to be optional (#205)
Browse files Browse the repository at this point in the history
* allow modifier field to be optional

* update module length to 200
  • Loading branch information
yads authored and dblock committed Dec 7, 2017
1 parent 8455818 commit 487d4fe
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 12 deletions.
2 changes: 1 addition & 1 deletion .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Metrics/MethodLength:
# Offense count: 2
# Configuration parameters: CountComments.
Metrics/ModuleLength:
Max: 176
Max: 200

# Offense count: 4
Metrics/PerceivedComplexity:
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* [#208](https://github.com/mongoid/mongoid-history/pull/208): Fix: history tracks fields declared after `track_history` - [@mikwat](https://github.com/mikwat).
* [#210](https://github.com/mongoid/mongoid-history/pull/210): Do not track unmodified embedded relations - [@jagdeepsingh](https://github.com/jagdeepsingh).
* Your contribution here.
* [#205](https://github.com/mongoid/mongoid-history/pull/205): Allow modifier field to be optional - [@yads](https://github.com/yads).

### 0.7.0 (2017/11/14)

Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ when /3/
else
gem 'mongoid', version
end
gem 'mongoid-compatibility'

group :development, :test do
gem 'bundler'
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ class Post
# telling Mongoid::History how you want to track changes
# dynamic fields will be tracked automatically (for MongoId 4.0+ you should include Mongoid::Attributes::Dynamic to your model)
track_history :on => [:title, :body], # track title and body fields only, default is :all
:modifier_field => :modifier, # adds "belongs_to :modifier" to track who made the change, default is :modifier
:modifier_field => :modifier, # adds "belongs_to :modifier" to track who made the change, default is :modifier, set to nil to not create modifier_field
:modifier_field_inverse_of => :nil, # adds an ":inverse_of" option to the "belongs_to :modifier" relation, default is not set
:modifier_field_optional => true, # marks the modifier relationship as optional (requires Mongoid 6 or higher)
:version_field => :version, # adds "field :version, :type => Integer" to track current version, default is :version
:track_create => false, # track document creation, default is false
:track_update => true, # track document updates, default is true
Expand Down
21 changes: 15 additions & 6 deletions lib/mongoid/history/trackable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ def track_history(options = {})

field history_options.options[:version_field].to_sym, type: Integer

belongs_to_modifier_options = { class_name: Mongoid::History.modifier_class_name }
belongs_to_modifier_options[:inverse_of] = options[:modifier_field_inverse_of] if history_options.options.key?(:modifier_field_inverse_of)
belongs_to history_options.options[:modifier_field].to_sym, belongs_to_modifier_options
unless history_options.options[:modifier_field].nil?
belongs_to_modifier_options = { class_name: Mongoid::History.modifier_class_name }
belongs_to_modifier_options[:inverse_of] = history_options.options[:modifier_field_inverse_of] if history_options.options.key?(:modifier_field_inverse_of)
belongs_to_modifier_options[:optional] = true if history_options.options[:modifier_field_optional] && Mongoid::Compatibility::Version.mongoid6_or_newer?
belongs_to history_options.options[:modifier_field].to_sym, belongs_to_modifier_options
end

include MyInstanceMethods
extend SingletonMethods
Expand Down Expand Up @@ -218,11 +221,12 @@ def modified_attributes_for_destroy
def history_tracker_attributes(action)
return @history_tracker_attributes if @history_tracker_attributes

modifier_field = history_trackable_options[:modifier_field]
@history_tracker_attributes = {
association_chain: traverse_association_chain,
scope: related_scope,
modifier: send(history_trackable_options[:modifier_field])
scope: related_scope
}
@history_tracker_attributes[:modifier] = send(modifier_field) if modifier_field

original, modified = transform_changes(modified_attributes_for_action(action))

Expand Down Expand Up @@ -424,7 +428,12 @@ def tracked_fields
#
# @return [ Array < String > ] the list of reserved database field names
def reserved_tracked_fields
@reserved_tracked_fields ||= ['_id', history_trackable_options[:version_field].to_s, "#{history_trackable_options[:modifier_field]}_id"]
@reserved_tracked_fields ||= begin
fields = ['_id', history_trackable_options[:version_field].to_s]
modifier_field = history_trackable_options[:modifier_field]
fields << "#{modifier_field}_id" if modifier_field
fields
end
end

def field_formats
Expand Down
10 changes: 7 additions & 3 deletions lib/mongoid/history/tracker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ module Tracker
field :version, type: Integer
field :action, type: String
field :scope, type: String
belongs_to :modifier, class_name: Mongoid::History.modifier_class_name
modifier_options = {
class_name: Mongoid::History.modifier_class_name
}
modifier_options[:optional] = true if Mongoid::Compatibility::Version.mongoid6_or_newer?
belongs_to :modifier, modifier_options

index(scope: 1)
index(association_chain: 1)
Expand Down Expand Up @@ -50,7 +54,7 @@ def undo_attr(modifier)
undo_hash = affected.easy_unmerge(modified)
undo_hash.easy_merge!(original)
modifier_field = trackable.history_trackable_options[:modifier_field]
undo_hash[modifier_field] = modifier
undo_hash[modifier_field] = modifier if modifier_field
(modified.keys - undo_hash.keys).each do |k|
undo_hash[k] = nil
end
Expand All @@ -61,7 +65,7 @@ def redo_attr(modifier)
redo_hash = affected.easy_unmerge(original)
redo_hash.easy_merge!(modified)
modifier_field = trackable.history_trackable_options[:modifier_field]
redo_hash[modifier_field] = modifier
redo_hash[modifier_field] = modifier if modifier_field
localize_keys(redo_hash)
end

Expand Down
2 changes: 1 addition & 1 deletion mongoid-history.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ Gem::Specification.new do |s|

s.add_runtime_dependency 'easy_diff'
s.add_runtime_dependency 'mongoid', '>= 3.0'
s.add_runtime_dependency 'mongoid-compatibility'
s.add_runtime_dependency 'mongoid-compatibility', '>= 0.5.1'
s.add_runtime_dependency 'activesupport'
end
43 changes: 43 additions & 0 deletions spec/unit/trackable_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,16 @@ class HistoryTracker
end

describe '#track_history' do
class MyModelWithNoModifier
include Mongoid::Document
include Mongoid::History::Trackable
field :foo
end

before :all do
MyModel.track_history
@persisted_history_options = Mongoid::History.trackable_class_options
MyModelWithNoModifier.track_history modifier_field: nil
end
before(:each) { Mongoid::History.trackable_class_options = @persisted_history_options }
let(:expected_option) do
Expand Down Expand Up @@ -72,6 +79,31 @@ class HistoryTracker
expect(MyModel.history_trackable_options).to eq(expected_option)
end

describe '#modifier' do
context 'modifier_field set to nil' do
it 'should not have a modifier relationship' do
expect(MyModelWithNoModifier.reflect_on_association(:modifier)).to be_nil
end
end

context 'modifier_field_optional true' do
class MyModelWithOptionalModifier
include Mongoid::Document
include Mongoid::History::Trackable
field :foo
end

it 'marks modifier relationship optional' do
MyModelWithOptionalModifier.track_history modifier_field_optional: true
if Mongoid::Compatibility::Version.mongoid6_or_newer?
expect(MyModelWithOptionalModifier.reflect_on_association(:modifier)[:optional]).to be true
else
expect(MyModelWithOptionalModifier.reflect_on_association(:modifier)).not_to be_nil
end
end
end
end

describe '#tracked_fields' do
it 'should return the tracked field list' do
expect(MyModel.tracked_fields).to eq(regular_fields)
Expand All @@ -82,6 +114,10 @@ class HistoryTracker
it 'should return the protected field list' do
expect(MyModel.reserved_tracked_fields).to eq(reserved_fields)
end

it 'should not include modifier_field if not specified' do
expect(MyModelWithNoModifier.reserved_tracked_fields).not_to include('modifier')
end
end

describe '#tracked_fields_for_action' do
Expand Down Expand Up @@ -628,13 +664,20 @@ def self.name
before :all do
MyModel.track_history(on: :foo, track_create: true)
@persisted_history_options = Mongoid::History.trackable_class_options
MyModelWithNoModifier.track_history modifier_field: nil
end
before(:each) { Mongoid::History.trackable_class_options = @persisted_history_options }

it 'should create history' do
expect { MyModel.create!(foo: 'bar') }.to change(Tracker, :count).by(1)
end

context 'no modifier_field' do
it 'should create history' do
expect { MyModelWithNoModifier.create!(foo: 'bar').to change(Tracker, :count).by(1) }
end
end

it 'should not create history when error raised' do
expect(MyModel).to receive(:create!).and_raise(StandardError)
expect do
Expand Down

0 comments on commit 487d4fe

Please sign in to comment.