paper_trail 1.5.2 → 1.5.3
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/README.md +63 -2
- data/VERSION +1 -1
- data/lib/generators/paper_trail/USAGE +2 -0
- data/lib/generators/paper_trail/paper_trail_generator.rb +24 -0
- data/lib/generators/paper_trail/templates/create_versions.rb +18 -0
- data/lib/paper_trail.rb +0 -2
- data/paper_trail.gemspec +5 -2
- data/test/paper_trail_model_test.rb +57 -0
- data/test/schema.rb +13 -0
- metadata +7 -4
data/README.md
CHANGED
@@ -25,7 +25,7 @@ PaperTrail lets you track changes to your models' data. It's good for auditing
|
|
25
25
|
|
26
26
|
## Rails Version
|
27
27
|
|
28
|
-
|
28
|
+
Works on Rails 3 and Rails 2.3. Probably works on Rails 2.2 and 2.1.
|
29
29
|
|
30
30
|
|
31
31
|
## Basic Usage
|
@@ -212,6 +212,48 @@ To find out who made a `version`'s object look that way, use `version.originator
|
|
212
212
|
>> last_version.terminator # 'Bob'
|
213
213
|
|
214
214
|
|
215
|
+
## Has-Many-Through Associations
|
216
|
+
|
217
|
+
PaperTrail can track most changes to the join table. Specifically it can track all additions but it can only track removals which fire the `after_destroy` callback on the join table. Here are some examples:
|
218
|
+
|
219
|
+
Given these models:
|
220
|
+
|
221
|
+
class Book < ActiveRecord::Base
|
222
|
+
has_many :authorships, :dependent => :destroy
|
223
|
+
has_many :authors, :through => :authorships, :source => :person
|
224
|
+
has_paper_trail
|
225
|
+
end
|
226
|
+
|
227
|
+
class Authorship < ActiveRecord::Base
|
228
|
+
belongs_to :book
|
229
|
+
belongs_to :person
|
230
|
+
has_paper_trail # NOTE
|
231
|
+
end
|
232
|
+
|
233
|
+
class Person < ActiveRecord::Base
|
234
|
+
has_many :authorships, :dependent => :destroy
|
235
|
+
has_many :books, :through => :authorships
|
236
|
+
has_paper_trail
|
237
|
+
end
|
238
|
+
|
239
|
+
Then each of the following will store authorship versions:
|
240
|
+
|
241
|
+
>> @book.authors << @dostoyevsky
|
242
|
+
>> @book.authors.create :name => 'Tolstoy'
|
243
|
+
>> @book.authorships.last.destroy
|
244
|
+
>> @book.authorships.clear
|
245
|
+
|
246
|
+
But none of these will:
|
247
|
+
|
248
|
+
>> @book.authors.delete @tolstoy
|
249
|
+
>> @book.author_ids = [@solzhenistyn.id, @dostoyevsky.id]
|
250
|
+
>> @book.authors = []
|
251
|
+
|
252
|
+
Having said that, you can probably (I haven't tested it myself) get the first one (`@book.authors.delete @tolstoy`) working with this [monkey patch](http://stackoverflow.com/questions/2381033/how-to-create-a-full-audit-log-in-rails-for-every-table/2381411#2381411). Many thanks to Danny Trelogan for pointing it out.
|
253
|
+
|
254
|
+
There may be a way to store authorship versions, probably using association callbacks, no matter how the collection is manipulated but I haven't found it yet. Let me know if you do.
|
255
|
+
|
256
|
+
|
215
257
|
## Storing metadata
|
216
258
|
|
217
259
|
You can store arbitrary model-level metadata alongside each version like this:
|
@@ -315,9 +357,27 @@ Over time your `versions` table will grow to an unwieldy size. Because each ver
|
|
315
357
|
|
316
358
|
## Installation
|
317
359
|
|
360
|
+
### Rails 3
|
361
|
+
|
362
|
+
1. Install PaperTrail as a gem via your `Gemfile`:
|
363
|
+
|
364
|
+
`gem 'paper_trail'`
|
365
|
+
|
366
|
+
2. Generate a migration which will add a `versions` table to your database.
|
367
|
+
|
368
|
+
`rails generate paper_trail`
|
369
|
+
|
370
|
+
3. Run the migration.
|
371
|
+
|
372
|
+
`rake db:migrate`
|
373
|
+
|
374
|
+
4. Add `has_paper_trail` to the models you want to track.
|
375
|
+
|
376
|
+
### Rails 2
|
377
|
+
|
318
378
|
1. Install PaperTrail as a gem via your `config/environment.rb`:
|
319
379
|
|
320
|
-
`config.gem 'paper_trail'
|
380
|
+
`config.gem 'paper_trail'`
|
321
381
|
|
322
382
|
2. Generate a migration which will add a `versions` table to your database.
|
323
383
|
|
@@ -353,6 +413,7 @@ Many thanks to:
|
|
353
413
|
* [Jeremy Weiskotten](http://github.com/jeremyw)
|
354
414
|
* [Phan Le](http://github.com/revo)
|
355
415
|
* [jdrucza](http://github.com/jdrucza)
|
416
|
+
* [conickal](http://github.com/conickal)
|
356
417
|
|
357
418
|
|
358
419
|
## Inspirations
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.5.
|
1
|
+
1.5.3
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rails/generators/named_base'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
|
4
|
+
class PaperTrailGenerator < Rails::Generators::NamedBase
|
5
|
+
include Rails::Generators::Migration
|
6
|
+
|
7
|
+
desc "Generates (but does not run) a migration to add a versions table."
|
8
|
+
source_root File.expand_path('../templates', __FILE__)
|
9
|
+
argument :name, :type => :string, :default => "create_versions"
|
10
|
+
|
11
|
+
# Implement the required interface for Rails::Generators::Migration.
|
12
|
+
# taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
|
13
|
+
def self.next_migration_number(dirname)
|
14
|
+
if ActiveRecord::Base.timestamped_migrations
|
15
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
16
|
+
else
|
17
|
+
"%.3d" % (current_migration_number(dirname) + 1)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_migration_file
|
22
|
+
migration_template 'create_versions.rb', 'db/migrate/create_versions.rb'
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class CreateVersions < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :versions do |t|
|
4
|
+
t.string :item_type, :null => false
|
5
|
+
t.integer :item_id, :null => false
|
6
|
+
t.string :event, :null => false
|
7
|
+
t.string :whodunnit
|
8
|
+
t.text :object
|
9
|
+
t.datetime :created_at
|
10
|
+
end
|
11
|
+
add_index :versions, [:item_type, :item_id]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.down
|
15
|
+
remove_index :versions, [:item_type, :item_id]
|
16
|
+
drop_table :versions
|
17
|
+
end
|
18
|
+
end
|
data/lib/paper_trail.rb
CHANGED
data/paper_trail.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{paper_trail}
|
8
|
-
s.version = "1.5.
|
8
|
+
s.version = "1.5.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Andy Stewart"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-10-11}
|
13
13
|
s.email = %q{boss@airbladesoftware.com}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"README.md"
|
@@ -25,6 +25,9 @@ Gem::Specification.new do |s|
|
|
25
25
|
"generators/paper_trail/templates/create_versions.rb",
|
26
26
|
"init.rb",
|
27
27
|
"install.rb",
|
28
|
+
"lib/generators/paper_trail/USAGE",
|
29
|
+
"lib/generators/paper_trail/paper_trail_generator.rb",
|
30
|
+
"lib/generators/paper_trail/templates/create_versions.rb",
|
28
31
|
"lib/paper_trail.rb",
|
29
32
|
"lib/paper_trail/config.rb",
|
30
33
|
"lib/paper_trail/controller.rb",
|
@@ -24,6 +24,24 @@ class Article < ActiveRecord::Base
|
|
24
24
|
:article_id => Proc.new { |article| article.id } }
|
25
25
|
end
|
26
26
|
|
27
|
+
class Book < ActiveRecord::Base
|
28
|
+
has_many :authorships, :dependent => :destroy
|
29
|
+
has_many :authors, :through => :authorships, :source => :person
|
30
|
+
has_paper_trail
|
31
|
+
end
|
32
|
+
|
33
|
+
class Authorship < ActiveRecord::Base
|
34
|
+
belongs_to :book
|
35
|
+
belongs_to :person
|
36
|
+
has_paper_trail
|
37
|
+
end
|
38
|
+
|
39
|
+
class Person < ActiveRecord::Base
|
40
|
+
has_many :authorships, :dependent => :destroy
|
41
|
+
has_many :books, :through => :authorships
|
42
|
+
has_paper_trail
|
43
|
+
end
|
44
|
+
|
27
45
|
|
28
46
|
class HasPaperTrailModelTest < Test::Unit::TestCase
|
29
47
|
load_schema
|
@@ -586,5 +604,44 @@ class HasPaperTrailModelTest < Test::Unit::TestCase
|
|
586
604
|
end
|
587
605
|
end
|
588
606
|
|
607
|
+
context ":has_many :through" do
|
608
|
+
setup do
|
609
|
+
@book = Book.create :title => 'War and Peace'
|
610
|
+
@dostoyevsky = Person.create :name => 'Dostoyevsky'
|
611
|
+
@solzhenitsyn = Person.create :name => 'Solzhenitsyn'
|
612
|
+
end
|
613
|
+
|
614
|
+
should 'store version on source <<' do
|
615
|
+
count = Version.count
|
616
|
+
@book.authors << @dostoyevsky
|
617
|
+
assert_equal 1, Version.count - count
|
618
|
+
assert_equal Version.last, @book.authorships.first.versions.first
|
619
|
+
end
|
620
|
+
|
621
|
+
should 'store version on source create' do
|
622
|
+
count = Version.count
|
623
|
+
@book.authors.create :name => 'Tolstoy'
|
624
|
+
assert_equal 2, Version.count - count
|
625
|
+
assert_same_elements [Person.last, Authorship.last], [Version.all[-2].item, Version.last.item]
|
626
|
+
end
|
627
|
+
|
628
|
+
should 'store version on join destroy' do
|
629
|
+
@book.authors << @dostoyevsky
|
630
|
+
count = Version.count
|
631
|
+
@book.authorships(true).last.destroy
|
632
|
+
assert_equal 1, Version.count - count
|
633
|
+
assert_equal @book, Version.last.reify.book
|
634
|
+
assert_equal @dostoyevsky, Version.last.reify.person
|
635
|
+
end
|
636
|
+
|
637
|
+
should 'store version on join clear' do
|
638
|
+
@book.authors << @dostoyevsky
|
639
|
+
count = Version.count
|
640
|
+
@book.authorships(true).clear
|
641
|
+
assert_equal 1, Version.count - count
|
642
|
+
assert_equal @book, Version.last.reify.book
|
643
|
+
assert_equal @dostoyevsky, Version.last.reify.person
|
644
|
+
end
|
645
|
+
end
|
589
646
|
|
590
647
|
end
|
data/test/schema.rb
CHANGED
@@ -49,4 +49,17 @@ ActiveRecord::Schema.define(:version => 0) do
|
|
49
49
|
t.string :content
|
50
50
|
end
|
51
51
|
|
52
|
+
create_table :books, :force => true do |t|
|
53
|
+
t.string :title
|
54
|
+
end
|
55
|
+
|
56
|
+
create_table :authorships, :force => true do |t|
|
57
|
+
t.integer :book_id
|
58
|
+
t.integer :person_id
|
59
|
+
end
|
60
|
+
|
61
|
+
create_table :people, :force => true do |t|
|
62
|
+
t.string :name
|
63
|
+
end
|
64
|
+
|
52
65
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paper_trail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 5
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 5
|
9
|
-
-
|
10
|
-
version: 1.5.
|
9
|
+
- 3
|
10
|
+
version: 1.5.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andy Stewart
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-10-11 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -38,6 +38,9 @@ files:
|
|
38
38
|
- generators/paper_trail/templates/create_versions.rb
|
39
39
|
- init.rb
|
40
40
|
- install.rb
|
41
|
+
- lib/generators/paper_trail/USAGE
|
42
|
+
- lib/generators/paper_trail/paper_trail_generator.rb
|
43
|
+
- lib/generators/paper_trail/templates/create_versions.rb
|
41
44
|
- lib/paper_trail.rb
|
42
45
|
- lib/paper_trail/config.rb
|
43
46
|
- lib/paper_trail/controller.rb
|