Changing the :clean_versions! method on the Cleaner module so that it accepts an options hash as an argument, and additional configurable options.

This commit is contained in:
Ben Atkins 2013-07-31 13:46:25 -04:00
parent 9e7ebc17d7
commit 087840932d
2 changed files with 131 additions and 50 deletions

View File

@ -1,14 +1,19 @@
module PaperTrail
module Cleaner
# Deletes all versions that were created on a given date except the last `keep_int` versions.
# `date` argument should receive either an object of type `Date` or `:all` (which will clean versions on all dates).
def clean_versions!(keep_int = 1, date = :all)
version_hash = gather_versions(date)
version_hash.each do |item_id, versions|
grouping_by_date = versions.group_by { |v| v.created_at.to_date } # now group the versions by date
grouping_by_date.each do |date, versions|
versions.pop(keep_int)
# Destroys all but the most recent version(s) for items on a given date (or on all dates). Useful for deleting drafts.
#
# Options:
# :keeping An `integer` indicating the number of versions to be kept for each item per date.
# Defaults to `1`.
# :date Should either be a `Date` object specifying which date to destroy versions for or `:all`,
# which will specify that all dates should be cleaned. Defaults to `:all`.
# :item_id The `id` for the item to be cleaned on, or `nil`, which causes all items to be cleaned.
# Defaults to `nil`.
def clean_versions!(options = {})
options = {:keeping => 1, :date => :all}.merge(options)
gather_versions(options[:item_id], options[:date]).each do |item_id, versions|
versions.group_by { |v| v.created_at.to_date }.each do |date, versions| # now group the versions by date and iterate through those
versions.pop(options[:keeping]) # remove the number of versions we wish to keep from the collection of versions prior to destruction
versions.map(&:destroy)
end
end
@ -16,12 +21,13 @@ module PaperTrail
private
# Returns a hash of versions in this format: {:item_id => PaperTrail::Version}
def gather_versions(date)
raise "`date` argument must receive a Timestamp or `:all`" unless date == :all || date.respond_to?(:to_time)
versions = date == :all ? Version.all : Version.between(date, date+1.day)
# Returns a hash of versions grouped by the `item_id` attribute formatted like this: {:item_id => PaperTrail::Version}.
# If `item_id` or `date` is set, versions will be narrowed to those pointing at items with those ids that were created on specified date.
def gather_versions(item_id = nil, date = :all)
raise "`date` argument must receive a Timestamp or `:all`" unless date == :all || date.respond_to?(:to_date)
versions = item_id ? PaperTrail::Version.where(:item_id => item_id) : PaperTrail::Version
versions = date == :all ? versions.all : versions.between(date.to_date, date.to_date + 1.day)
versions.group_by(&:item_id)
end
end
end

View File

@ -3,27 +3,23 @@ require 'test_helper'
class PaperTrailCleanerTest < ActiveSupport::TestCase
setup do
@animal = Animal.create :name => 'Animal'
@animal.update_attributes :name => 'Animal from the Muppets'
@animal.update_attributes :name => 'Animal Muppet'
@dog = Dog.create :name => 'Snoopy'
@dog.update_attributes :name => 'Scooby'
@dog.update_attributes :name => 'Scooby Doo'
@cat = Cat.create :name => 'Garfield'
@cat.update_attributes :name => 'Garfield (I hate Mondays)'
@cat.update_attributes :name => 'Garfield The Cat'
@animals = [@animal, @dog, @cat]
@animals = [@animal = Animal.new, @dog = Dog.new, @cat = Cat.new]
@animals.each do |animal|
3.times { animal.update_attribute(:name, Faker::Name.name) }
end
end
test 'Baseline' do
assert_equal 9, PaperTrail::Version.count
@animals.each { |animal| assert_equal 3, animal.versions.size }
end
context 'Cleaner' do
context '`clean_versions!` method' do
context '`clean_versions!` method' do
should 'be extended by `PaperTrail` module' do
assert_respond_to PaperTrail, :clean_versions!
end
context 'No options provided' do
should 'removes extra versions for each item' do
PaperTrail.clean_versions!
assert_equal 3, PaperTrail::Version.count
@ -35,34 +31,113 @@ class PaperTrailCleanerTest < ActiveSupport::TestCase
PaperTrail.clean_versions!
assert_equal most_recent_version_names, @animals.map { |animal| animal.versions.last.reify.name }
end
end
context '`keep_int` argument' do
should 'modifies the number of versions ommitted from destruction' do
PaperTrail.clean_versions!(2)
assert_equal 6, PaperTrail::Version.all.count
@animals.each { |animal| assert_equal 2, animal.versions.size }
context '`:keeping` option' do
should 'modifies the number of versions ommitted from destruction' do
PaperTrail.clean_versions!(:keeping => 2)
assert_equal 6, PaperTrail::Version.all.count
@animals.each { |animal| assert_equal 2, animal.versions.size }
end
end
context '`:date` option' do
setup do
@animal.versions.each { |ver| ver.update_attribute(:created_at, ver.created_at - 1.day) }
@date = @animal.versions.first.created_at.to_date
@animal.update_attribute(:name, Faker::Name.name)
end
should 'restrict the versions destroyed to those that were created on the date provided' do
assert_equal 10, PaperTrail::Version.count
assert_equal 4, @animal.versions.size
assert_equal 3, @animal.versions_between(@date, @date + 1.day).size
PaperTrail.clean_versions!(:date => @date)
assert_equal 8, PaperTrail::Version.count
assert_equal 2, @animal.versions(true).size
assert_equal @date, @animal.versions.first.created_at.to_date
assert_not_same @date, @animal.versions.last.created_at.to_date
end
end
context '`:item_id` option' do
context 'single ID received' do
should 'restrict the versions destroyed to the versions for the Item with that ID' do
PaperTrail.clean_versions!(:item_id => @animal.id)
assert_equal 1, @animal.versions.size
assert_equal 7, PaperTrail::Version.count
end
end
context '`date` argument' do
setup do
@animal.versions.each { |ver| ver.update_attribute(:created_at, ver.created_at - 1.day) }
@date = @animal.versions.first.created_at.to_date
@animal.update_attribute(:name, 'Muppet')
end
should 'restrict the version destroyed to those that were created on the date provided' do
assert_equal 10, PaperTrail::Version.count
assert_equal 4, @animal.versions.size
assert_equal 3, @animal.versions_between(@date, @date + 1.day).size
PaperTrail.clean_versions!(1, @date)
assert_equal 8, PaperTrail::Version.count
assert_equal 2, @animal.versions(true).size
assert_equal @date, @animal.versions.first.created_at.to_date
assert_equal @date + 1.day, @animal.versions.last.created_at.to_date
context "collection of ID's received" do
should "restrict the versions destroyed to the versions for the Item with those ID's" do
PaperTrail.clean_versions!(:item_id => [@animal.id, @dog.id])
assert_equal 1, @animal.versions.size
assert_equal 1, @dog.versions.size
assert_equal 5, PaperTrail::Version.count
end
end
end
end
context 'options combinations' do # additional tests to cover combinations of options
context '`:date`' do
setup do
[@animal, @dog].each do |animal|
animal.versions.each { |ver| ver.update_attribute(:created_at, ver.created_at - 1.day) }
animal.update_attribute(:name, Faker::Name.name)
end
@date = @animal.versions.first.created_at.to_date
end
should 'Baseline' do
assert_equal 11, PaperTrail::Version.count
[@animal, @dog].each do |animal|
assert_equal 4, animal.versions.size
assert_equal 3, animal.versions.between(@date, @date+1.day).size
end
end
context 'and `:keeping`' do
should 'restrict cleaning properly' do
PaperTrail.clean_versions!(:date => @date, :keeping => 2)
[@animal, @dog].each do |animal|
animal.versions.reload # reload the association to pick up the destructions made by the `Cleaner`
assert_equal 3, animal.versions.size
assert_equal 2, animal.versions.between(@date, @date+1.day).size
end
assert_equal 9, PaperTrail::Version.count # ensure that the versions for the `@cat` instance wasn't touched
end
end
context 'and `:item_id`' do
should 'restrict cleaning properly' do
PaperTrail.clean_versions!(:date => @date, :item_id => @dog.id)
@dog.versions.reload # reload the association to pick up the destructions made by the `Cleaner`
assert_equal 2, @dog.versions.size
assert_equal 1, @dog.versions.between(@date, @date+1.day).size
assert_equal 9, PaperTrail::Version.count # ensure the versions for other animals besides `@animal` weren't touched
end
end
context ', `:item_id`, and `:keeping`' do
should 'restrict cleaning properly' do
PaperTrail.clean_versions!(:date => @date, :item_id => @dog.id, :keeping => 2)
@dog.versions.reload # reload the association to pick up the destructions made by the `Cleaner`
assert_equal 3, @dog.versions.size
assert_equal 2, @dog.versions.between(@date, @date+1.day).size
assert_equal 10, PaperTrail::Version.count # ensure the versions for other animals besides `@animal` weren't touched
end
end
end
context '`:keeping` and `:item_id`' do
should 'restrict cleaning properly' do
PaperTrail.clean_versions!(:keeping => 2, :item_id => @animal.id)
assert_equal 2, @animal.versions.size
assert_equal 8, PaperTrail::Version.count # ensure the versions for other animals besides `@animal` weren't touched
end
end
end
end # clean_versions! method
end