conditional tracking of only/ignore
This commit is contained in:
parent
2c3f330521
commit
567f21b5a7
18
README.md
18
README.md
|
@ -268,7 +268,7 @@ You can ignore changes to certain attributes like this:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
class Article < ActiveRecord::Base
|
class Article < ActiveRecord::Base
|
||||||
has_paper_trail :ignore => [:title, :rating]
|
has_paper_trail :ignore => [:title, :rating => Proc.new { |obj| obj.raiting == 0 } ]
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -277,10 +277,13 @@ This means that changes to just the `title` or `rating` will not store another v
|
||||||
```ruby
|
```ruby
|
||||||
>> a = Article.create
|
>> a = Article.create
|
||||||
>> a.versions.length # 1
|
>> a.versions.length # 1
|
||||||
>> a.update_attributes :title => 'My Title', :rating => 3
|
>> a.update_attributes :title => 'My Title', :rating => 0
|
||||||
>> a.versions.length # 1
|
>> a.versions.length # 1
|
||||||
>> a.update_attributes :title => 'Greeting', :content => 'Hello'
|
>> a.update_attributes :title => 'My Title', :rating => 3
|
||||||
>> a.versions.length # 2
|
>> a.versions.length # 2
|
||||||
|
>> a.previous_version.raiting # nil
|
||||||
|
>> a.update_attributes :title => 'Greeting', :content => 'Hello'
|
||||||
|
>> a.versions.length # 3
|
||||||
>> a.previous_version.title # 'My Title'
|
>> a.previous_version.title # 'My Title'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -288,11 +291,11 @@ Or, you can specify a list of all attributes you care about:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
class Article < ActiveRecord::Base
|
class Article < ActiveRecord::Base
|
||||||
has_paper_trail :only => [:title]
|
has_paper_trail :only => [:title, :author => Proc.new { |obj| obj.author.present? }]
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
This means that only changes to the `title` will save a version of the article:
|
This means that only changes to the `title` and non-empty `author` will save a version of the article:
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
>> a = Article.create
|
>> a = Article.create
|
||||||
|
@ -302,6 +305,11 @@ This means that only changes to the `title` will save a version of the article:
|
||||||
>> a.update_attributes :content => 'Hello'
|
>> a.update_attributes :content => 'Hello'
|
||||||
>> a.versions.length # 2
|
>> a.versions.length # 2
|
||||||
>> a.previous_version.content # nil
|
>> a.previous_version.content # nil
|
||||||
|
>> a.update_attributes :author => 'Me'
|
||||||
|
>> a.versions.length # 3
|
||||||
|
>> a.update_attributes :author => ''
|
||||||
|
>> a.versions.length # 3
|
||||||
|
>> a.previous_version.author # 'Me'
|
||||||
```
|
```
|
||||||
|
|
||||||
Passing both `:ignore` and `:only` options will result in the article being saved if a changed attribute is included in `:only` but not in `:ignore`.
|
Passing both `:ignore` and `:only` options will result in the article being saved if a changed attribute is included in `:only` but not in `:ignore`.
|
||||||
|
|
|
@ -15,8 +15,12 @@ module PaperTrail
|
||||||
# `:create`, `:update`, `:destroy` as desired.
|
# `:create`, `:update`, `:destroy` as desired.
|
||||||
# :class_name the name of a custom Version class. This class should inherit from Version.
|
# :class_name the name of a custom Version class. This class should inherit from Version.
|
||||||
# :ignore an array of attributes for which a new `Version` will not be created if only they change.
|
# :ignore an array of attributes for which a new `Version` will not be created if only they change.
|
||||||
|
# it can also has a Hash as an item: the key is the attribute to ignore, the value - a Proc
|
||||||
|
# given a current state of object before save, only if it results in true - attribute will be ignored
|
||||||
# :if, :unless Procs that allow to specify conditions when to save versions for an object
|
# :if, :unless Procs that allow to specify conditions when to save versions for an object
|
||||||
# :only inverse of `ignore` - a new `Version` will be created only for these attributes if supplied
|
# :only inverse of `ignore` - a new `Version` will be created only for these attributes if supplied
|
||||||
|
# it can also has a Hash as an item: the key is the attribute to track, the value - a Proc
|
||||||
|
# given a current state of object before save, only if it results in true - attribute will create a version
|
||||||
# :skip fields to ignore completely. As with `ignore`, updates to these fields will not create
|
# :skip fields to ignore completely. As with `ignore`, updates to these fields will not create
|
||||||
# a new `Version`. In addition, these fields will not be included in the serialized versions
|
# a new `Version`. In addition, these fields will not be included in the serialized versions
|
||||||
# of the object whenever a new `Version` is created.
|
# of the object whenever a new `Version` is created.
|
||||||
|
@ -46,7 +50,15 @@ module PaperTrail
|
||||||
|
|
||||||
[:ignore, :skip, :only].each do |k|
|
[:ignore, :skip, :only].each do |k|
|
||||||
paper_trail_options[k] =
|
paper_trail_options[k] =
|
||||||
([paper_trail_options[k]].flatten.compact || []).map &:to_s
|
([paper_trail_options[k]].flatten.compact || []).map do |attr|
|
||||||
|
if attr.is_a? Hash
|
||||||
|
Hash[attr.map do |attr_name, condition|
|
||||||
|
[attr_name.to_s, condition]
|
||||||
|
end]
|
||||||
|
else
|
||||||
|
attr.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
paper_trail_options[:meta] ||= {}
|
paper_trail_options[:meta] ||= {}
|
||||||
|
@ -284,12 +296,30 @@ module PaperTrail
|
||||||
end
|
end
|
||||||
|
|
||||||
def notably_changed
|
def notably_changed
|
||||||
only = self.class.paper_trail_options[:only]
|
only = []
|
||||||
|
self.class.paper_trail_options[:only].each do |attr|
|
||||||
|
if attr.is_a? Hash
|
||||||
|
attr.each do |attr_name, condition|
|
||||||
|
only << attr_name if condition.respond_to?(:call) && condition.call(self)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
only << attr
|
||||||
|
end
|
||||||
|
end
|
||||||
only.empty? ? changed_and_not_ignored : (changed_and_not_ignored & only)
|
only.empty? ? changed_and_not_ignored : (changed_and_not_ignored & only)
|
||||||
end
|
end
|
||||||
|
|
||||||
def changed_and_not_ignored
|
def changed_and_not_ignored
|
||||||
ignore = self.class.paper_trail_options[:ignore]
|
ignore = []
|
||||||
|
self.class.paper_trail_options[:ignore].each do |attr|
|
||||||
|
if attr.is_a? Hash
|
||||||
|
attr.each do |attr_name, condition|
|
||||||
|
ignore << attr_name if condition.respond_to?(:call) && condition.call(self)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
ignore << attr
|
||||||
|
end
|
||||||
|
end
|
||||||
skip = self.class.paper_trail_options[:skip]
|
skip = self.class.paper_trail_options[:skip]
|
||||||
changed - ignore - skip
|
changed - ignore - skip
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
class Article < ActiveRecord::Base
|
class Article < ActiveRecord::Base
|
||||||
has_paper_trail :ignore => :title,
|
has_paper_trail :ignore => [:title, { :abstract => Proc.new { |obj| ['ignore abstract', 'Other abstract'].include? obj.abstract } }],
|
||||||
:only => [:content],
|
:only => [:content, { :abstract => Proc.new { |obj| obj.abstract.present? } }],
|
||||||
:skip => [:file_upload],
|
:skip => [:file_upload],
|
||||||
:meta => {
|
:meta => {
|
||||||
:answer => 42,
|
:answer => 42,
|
||||||
|
|
|
@ -11,8 +11,21 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
|
||||||
should 'not change the number of versions' do assert_equal(1, PaperTrail::Version.count) end
|
should 'not change the number of versions' do assert_equal(1, PaperTrail::Version.count) end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'which updates an ignored column and a selected column' do
|
context 'which updates an ignored column with truly Proc' do
|
||||||
setup { @article.update_attributes :title => 'My first title', :content => 'Some text here.' }
|
setup { @article.update_attributes :abstract => 'ignore abstract' }
|
||||||
|
should 'not change the number of versions' do assert_equal(1, PaperTrail::Version.count) end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'which updates an ignored column with falsy Proc' do
|
||||||
|
setup { @article.update_attributes :abstract => 'do not ignore abstract!' }
|
||||||
|
should 'change the number of versions' do assert_equal(2, PaperTrail::Version.count) end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'which updates an ignored column, ignored with truly Proc and a selected column' do
|
||||||
|
setup { @article.update_attributes :title => 'My first title',
|
||||||
|
:content => 'Some text here.',
|
||||||
|
:abstract => 'ignore abstract'
|
||||||
|
}
|
||||||
should 'change the number of versions' do assert_equal(2, PaperTrail::Version.count) end
|
should 'change the number of versions' do assert_equal(2, PaperTrail::Version.count) end
|
||||||
|
|
||||||
should "show the new version in the model's `versions` association" do
|
should "show the new version in the model's `versions` association" do
|
||||||
|
@ -24,6 +37,22 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'which updates an ignored column, ignored with falsy Proc and a selected column' do
|
||||||
|
setup { @article.update_attributes :title => 'My first title',
|
||||||
|
:content => 'Some text here.',
|
||||||
|
:abstract => 'do not ignore abstract'
|
||||||
|
}
|
||||||
|
should 'change the number of versions' do assert_equal(2, PaperTrail::Version.count) end
|
||||||
|
|
||||||
|
should "show the new version in the model's `versions` association" do
|
||||||
|
assert_equal(2, @article.versions.size)
|
||||||
|
end
|
||||||
|
|
||||||
|
should 'have stored only non-ignored attributes' do
|
||||||
|
assert_equal ({'content' => [nil, 'Some text here.'], 'abstract' => [nil, 'do not ignore abstract']}), @article.versions.last.changeset
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'which updates a selected column' do
|
context 'which updates a selected column' do
|
||||||
setup { @article.update_attributes :content => 'Some text here.' }
|
setup { @article.update_attributes :content => 'Some text here.' }
|
||||||
should 'change the number of versions' do assert_equal(2, PaperTrail::Version.count) end
|
should 'change the number of versions' do assert_equal(2, PaperTrail::Version.count) end
|
||||||
|
|
Loading…
Reference in New Issue