Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 577 lines (379 sloc) 23.842 kb
e9a8648c »
2009-05-27 First commit.
1 # PaperTrail
2
93270834 »
2009-06-23 Added info on reverting and undeleting.
3 PaperTrail lets you track changes to your models' data. It's good for auditing or versioning. You can see how a model looked at any stage in its lifecycle, revert it to any version, and even undelete it after it's been destroyed.
e9a8648c »
2009-05-27 First commit.
4
559eb91d »
2011-03-01 Link up Railscast.
5 There's an excellent [Railscast on implementing Undo with Paper Trail](http://railscasts.com/episodes/255-undo-with-paper-trail).
e9a8648c »
2009-05-27 First commit.
6
7 ## Features
8
9 * Stores every create, update and destroy.
55185cd4 »
2010-01-06 Store user-defined metadata.
10 * Does not store updates which don't change anything.
c93b364c »
2011-02-25 Update feature list in light of :only option.
11 * Allows you to specify attributes (by inclusion or exclusion) which must change for a Version to be stored.
e9a8648c »
2009-05-27 First commit.
12 * Allows you to get at every version, including the original, even once destroyed.
13 * Allows you to get at every version even if the schema has since changed.
3a4187b5 »
2010-02-18 Describe version_at in README. Add JW as contributor.
14 * Allows you to get at the version as of a particular time.
9728e315 »
2010-10-20 Automatically restore has_one associations.
15 * Automatically restores the `has_one` associations as they were at the time.
3036aa75 »
2010-03-19 Store controller info. Allow other current_user methods.
16 * Automatically records who was responsible via your controller. PaperTrail calls `current_user` by default, if it exists, but you can have it call any method you like.
e9a8648c »
2009-05-27 First commit.
17 * Allows you to set who is responsible at model-level (useful for migrations).
3036aa75 »
2010-03-19 Store controller info. Allow other current_user methods.
18 * Allows you to store arbitrary model-level metadata with each version (useful for filtering versions).
19 * Allows you to store arbitrary controller-level information with each version, e.g. remote IP.
4f4f8145 »
2010-03-19 Global enable/disable for PaperTrail.
20 * Can be turned off/on per class (useful for migrations).
21 * Can be turned off/on globally (useful for testing).
e9a8648c »
2009-05-27 First commit.
22 * No configuration necessary.
23 * Stores everything in a single database table (generates migration for you).
24 * Thoroughly tested.
9332ff25 »
2010-03-19 Make PaperTrail threadsafe.
25 * Threadsafe.
e9a8648c »
2009-05-27 First commit.
26
27
28 ## Rails Version
29
2b5dbe05 »
2011-03-01 Add note about Rails 2.3.
30 Works on Rails 3 and Rails 2.3. The Rails 3 code is on the `master` branch and tagged `v2.x`. The Rails 2.3 code is on the `rails2` branch and tagged `v1.x`. Please note I'm not adding new features to the Rails 2.3 codebase.
e9a8648c »
2009-05-27 First commit.
31
32
bfe96a71 »
2010-10-28 Add API summary as a quick reference.
33 ## API Summary
34
35 When you declare `has_paper_trail` in your model, you get these methods:
36
37 class Widget < ActiveRecord::Base
38 has_paper_trail # you can pass various options here
39 end
40
41 # Returns this widget's versions.
42 widget.versions
43
44 # Return the version this widget was reified from, or nil if it is live.
45 widget.version
46
47 # Returns true if this widget is the current, live one; or false if it is from a previous version.
48 widget.live?
49
50 # Returns who put the widget into its current state.
51 widget.originator
52
53 # Returns the widget (not a version) as it looked at the given timestamp.
54 widget.version_at(timestamp)
55
56 # Returns the widget (not a version) as it was most recently.
57 widget.previous_version
58
59 # Returns the widget (not a version) as it became next.
60 widget.next_version
61
62 # Turn PaperTrail off for all widgets.
63 Widget.paper_trail_off
64
65 # Turn PaperTrail on for all widgets.
66 Widget.paper_trail_on
67
68 And a `Version` instance has these methods:
69
70 # Returns the item restored from this version.
71 version.reify(options = {})
72
73 # Returns who put the item into the state stored in this version.
74 version.originator
75
76 # Returns who changed the item from the state it had in this version.
77 version.terminator
78 version.whodunnit
79
80 # Returns the next version.
81 version.next
82
83 # Returns the previous version.
84 version.previous
85
86 # Returns the index of this version in all the versions.
87 version.index
88
89 # Returns the event that caused this version (create|update|destroy).
90 version.event
91
92 In your controllers you can override these methods:
93
94 # Returns the user who is responsible for any changes that occur.
95 # Defaults to current_user.
96 user_for_paper_trail
97
98 # Returns any information about the controller or request that you want
99 # PaperTrail to store alongside any changes that occur.
100 info_for_paper_trail
101
102
e9a8648c »
2009-05-27 First commit.
103 ## Basic Usage
104
4da196ab »
2009-06-23 Expanded README.
105 PaperTrail is simple to use. Just add 15 characters to a model to get a paper trail of every `create`, `update`, and `destroy`.
e9a8648c »
2009-05-27 First commit.
106
107 class Widget < ActiveRecord::Base
108 has_paper_trail
109 end
110
111 This gives you a `versions` method which returns the paper trail of changes to your model.
112
113 >> widget = Widget.find 42
114 >> widget.versions # [<Version>, <Version>, ...]
115
116 Once you have a version, you can find out what happened:
117
118 >> v = widget.versions.last
119 >> v.event # 'update' (or 'create' or 'destroy')
120 >> v.whodunnit # '153' (if the update was via a controller and
121 # the controller has a current_user method,
122 # here returning the id of the current user)
123 >> v.created_at # when the update occurred
124 >> widget = v.reify # the widget as it was before the update;
125 # would be nil for a create event
126
4da196ab »
2009-06-23 Expanded README.
127 PaperTrail stores the pre-change version of the model, unlike some other auditing/versioning plugins, so you can retrieve the original version. This is useful when you start keeping a paper trail for models that already have records in the database.
e9a8648c »
2009-05-27 First commit.
128
129 >> widget = Widget.find 153
130 >> widget.name # 'Doobly'
4da196ab »
2009-06-23 Expanded README.
131
132 # Add has_paper_trail to Widget model.
133
e9a8648c »
2009-05-27 First commit.
134 >> widget.versions # []
135 >> widget.update_attributes :name => 'Wotsit'
136 >> widget.versions.first.reify.name # 'Doobly'
137 >> widget.versions.first.event # 'update'
138
4da196ab »
2009-06-23 Expanded README.
139 This also means that PaperTrail does not waste space storing a version of the object as it currently stands. The `versions` method gives you previous versions; to get the current one just call a finder on your `Widget` model as usual.
e9a8648c »
2009-05-27 First commit.
140
141 Here's a helpful table showing what PaperTrail stores:
142
143 <table>
144 <tr>
145 <th>Event</th>
146 <th>Model Before</th>
147 <th>Model After</th>
148 </tr>
149 <tr>
150 <td>create</td>
151 <td>nil</td>
152 <td>widget</td>
153 </tr>
154 <tr>
155 <td>update</td>
156 <td>widget</td>
157 <td>widget'</td>
158 <tr>
159 <td>destroy</td>
160 <td>widget</td>
161 <td>nil</td>
162 </tr>
163 </table>
164
4da196ab »
2009-06-23 Expanded README.
165 PaperTrail stores the values in the Model Before column. Most other auditing/versioning plugins store the After column.
166
167
7e34a81e »
2011-02-25 Changed the way that notable attributes are worked out to make better…
168 ## Choosing Attributes To Monitor
52981bfc »
2009-10-28 Optionally ignore attributes.
169
170 You can ignore changes to certain attributes like this:
171
172 class Article < ActiveRecord::Base
173 has_paper_trail :ignore => [:title, :rating]
174 end
175
176 This means that changes to just the `title` or `rating` will not store another version of the article. It does not mean that the `title` and `rating` attributes will be ignored if some other change causes a new `Version` to be crated. For example:
177
178 >> a = Article.create
179 >> a.versions.length # 1
180 >> a.update_attributes :title => 'My Title', :rating => 3
181 >> a.versions.length # 1
182 >> a.update_attributes :content => 'Hello'
183 >> a.versions.length # 2
184 >> a.versions.last.reify.title # 'My Title'
185
7e34a81e »
2011-02-25 Changed the way that notable attributes are worked out to make better…
186 Or, you can specify a list of all attributes you care about:
187
188 class Article < ActiveRecord::Base
189 has_paper_trail :only => [:title]
190 end
191
192 This means that only changes to the `title` will save a version of the article:
193
2519c2b9 »
2011-02-25 Whitespace.
194 >> a = Article.create
7e34a81e »
2011-02-25 Changed the way that notable attributes are worked out to make better…
195 >> a.versions.length # 1
196 >> a.update_attributes :title => 'My Title'
197 >> a.versions.length # 2
198 >> a.update_attributes :content => 'Hello'
199 >> a.versions.length # 2
2519c2b9 »
2011-02-25 Whitespace.
200
7e34a81e »
2011-02-25 Changed the way that notable attributes are worked out to make better…
201 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`.
52981bfc »
2009-10-28 Optionally ignore attributes.
202
2519c2b9 »
2011-02-25 Whitespace.
203
93270834 »
2009-06-23 Added info on reverting and undeleting.
204 ## Reverting And Undeleting A Model
4da196ab »
2009-06-23 Expanded README.
205
93270834 »
2009-06-23 Added info on reverting and undeleting.
206 PaperTrail makes reverting to a previous version easy:
4da196ab »
2009-06-23 Expanded README.
207
208 >> widget = Widget.find 42
93270834 »
2009-06-23 Added info on reverting and undeleting.
209 >> widget.update_attributes :name => 'Blah blah'
4da196ab »
2009-06-23 Expanded README.
210 # Time passes....
93270834 »
2009-06-23 Added info on reverting and undeleting.
211 >> widget = widget.versions.last.reify # the widget as it was before the update
212 >> widget.save # reverted
213
3a4187b5 »
2010-02-18 Describe version_at in README. Add JW as contributor.
214 Alternatively you can find the version at a given time:
215
216 >> widget = widget.version_at(1.day.ago) # the widget as it was one day ago
217 >> widget.save # reverted
218
219 Note `version_at` gives you the object, not a version, so you don't need to call `reify`.
220
93270834 »
2009-06-23 Added info on reverting and undeleting.
221 Undeleting is just as simple:
4da196ab »
2009-06-23 Expanded README.
222
93270834 »
2009-06-23 Added info on reverting and undeleting.
223 >> widget = Widget.find 42
224 >> widget.destroy
225 # Time passes....
4da196ab »
2009-06-23 Expanded README.
226 >> widget = Version.find(153).reify # the widget as it was before it was destroyed
227 >> widget.save # the widget lives!
228
559eb91d »
2011-03-01 Link up Railscast.
229 In fact you could use PaperTrail to implement an undo system, though I haven't had the opportunity yet to do it myself. However [Ryan Bates has](http://railscasts.com/episodes/255-undo-with-paper-trail)!
e9a8648c »
2009-05-27 First commit.
230
231
cc835027 »
2010-06-22 Navigate back to reified item's version.
232 ## Navigating Versions
233
b43400e3 »
2010-06-22 Navigate to an item's previous and next version.
234 You can call `previous_version` and `next_version` on an item to get it as it was/became. Note that these methods reify the item for you.
235
236 >> widget = Widget.find 42
237 >> widget.versions.length # 4 for example
238 >> widget = widget.previous_version # => widget == widget.versions.last.reify
239 >> widget = widget.previous_version # => widget == widget.versions[-2].reify
240 >> widget.next_version # => widget == widget.versions.last.reify
241 >> widget.next_version # nil
242
243 As an aside, I'm undecided about whether `widget.versions.last.next_version` should return `nil` or `self` (i.e. `widget`). Let me know if you have a view.
244
245 If instead you have a particular `version` of an item you can navigate to the previous and next versions.
cc835027 »
2010-06-22 Navigate back to reified item's version.
246
247 >> widget = Widget.find 42
248 >> version = widget.versions[-2] # assuming widget has several versions
249 >> previous = version.previous
250 >> next = version.next
251
252 You can find out which of an item's versions yours is:
253
254 >> current_version_number = version.index # 0-based
255
256 Finally, if you got an item by reifying one of its versions, you can navigate back to the version it came from:
257
258 >> latest_version = Widget.find(42).versions.last
259 >> widget = latest_version.reify
260 >> widget.version == latest_version # true
261
aa00ccae »
2010-10-21 Add convenience method to find out if instance is live.
262 You can find out whether a model instance is the current, live one -- or whether it came instead from a previous version -- with `live?`:
263
264 >> widget = Widget.find 42
265 >> widget.live? # true
266 >> widget = widget.versions.last.reify
267 >> widget.live? # false
268
cc835027 »
2010-06-22 Navigate back to reified item's version.
269
e9a8648c »
2009-05-27 First commit.
270 ## Finding Out Who Was Responsible For A Change
271
4da196ab »
2009-06-23 Expanded README.
272 If your `ApplicationController` has a `current_user` method, PaperTrail will store the value it returns in the `version`'s `whodunnit` column. Note that this column is a string so you will have to convert it to an integer if it's an id and you want to look up the user later on:
e9a8648c »
2009-05-27 First commit.
273
274 >> last_change = Widget.versions.last
275 >> user_who_made_the_change = User.find last_change.whodunnit.to_i
276
3036aa75 »
2010-03-19 Store controller info. Allow other current_user methods.
277 You may want PaperTrail to call a different method to find out who is responsible. To do so, override the `user_for_paper_trail` method in your controller like this:
278
279 class ApplicationController
280 def user_for_paper_trail
281 logged_in? ? current_member : 'Public user' # or whatever
282 end
283 end
284
e9a8648c »
2009-05-27 First commit.
285 In a migration or in `script/console` you can set who is responsible like this:
286
287 >> PaperTrail.whodunnit = 'Andy Stewart'
288 >> widget.update_attributes :name => 'Wibble'
289 >> widget.versions.last.whodunnit # Andy Stewart
290
f27763bf »
2010-06-28 Clarify who was responsible for changes.
291 N.B. A `version`'s `whodunnit` records who changed the object causing the `version` to be stored. Because a `version` stores the object as it looked before the change (see the table above), `whodunnit` returns who stopped the object looking like this -- not who made it look like this. Hence `whodunnit` is aliased as `terminator`.
292
293 To find out who made a `version`'s object look that way, use `version.originator`. And to find out who made a "live" object look like it does, use `originator` on the object.
294
295 >> widget = Widget.find 153 # assume widget has 0 versions
296 >> PaperTrail.whodunnit = 'Alice'
297 >> widget.update_attributes :name => 'Yankee'
298 >> widget.originator # 'Alice'
299 >> PaperTrail.whodunnit = 'Bob'
300 >> widget.update_attributes :name => 'Zulu'
301 >> widget.originator # 'Bob'
302 >> first_version, last_version = widget.versions.first, widget.versions.last
303 >> first_version.whodunnit # 'Alice'
304 >> first_version.originator # nil
305 >> first_version.terminator # 'Alice'
306 >> last_version.whodunnit # 'Bob'
307 >> last_version.originator # 'Alice'
308 >> last_version.terminator # 'Bob'
309
e9a8648c »
2009-05-27 First commit.
310
f664a454 »
2011-03-01 Add note about associations.
311 ## Associations
312
313 I haven't yet found a good way to get PaperTrail to automatically restore associations when you reify a model. See [here for a little more info](http://airbladesoftware.com/notes/undo-and-redo-with-papertrail).
314
315 If you can think of a good way to achieve this, please let me know.
316
317
9728e315 »
2010-10-20 Automatically restore has_one associations.
318 ## Has-One Associations
319
100eb53c »
2010-10-21 Improve automatic reification of has_one associations.
320 PaperTrail automatically restores `:has_one` associations as they were at (actually, 3 seconds before) the time.
9728e315 »
2010-10-20 Automatically restore has_one associations.
321
322 class Treasure < ActiveRecord::Base
323 has_one :location
324 end
325
326 >> treasure.amount # 100
327 >> treasure.location.latitude # 12.345
328
329 >> treasure.update_attributes :amount => 153
330 >> treasure.location.update_attributes :latitude => 54.321
331
332 >> t = treasure.versions.last.reify
333 >> t.amount # 100
334 >> t.location.latitude # 12.345
4cf3cb95 »
2010-10-20 Add caveat about has_one and transactions.
335
100eb53c »
2010-10-21 Improve automatic reification of has_one associations.
336 The implementation is complicated by the edge case where the parent and child are updated in one go, e.g. in one web request or database transaction. PaperTrail doesn't know about different models being updated "together", so you can't ask it definitively to get the child as it was before the joint parent-and-child update.
337
338 The correct solution is to make PaperTrail aware of requests or transactions (c.f. [Efficiency's transaction ID middleware](http://github.com/efficiency20/ops_middleware/blob/master/lib/e20/ops/middleware/transaction_id_middleware.rb)). In the meantime we work around the problem by finding the child as it was a few seconds before the parent was updated. By default we go 3 seconds before but you can change this by passing the `:has_one` option to `reify`:
339
340 >> t = treasure.versions.last.reify(:has_one => 1) # look back 1 second instead of 3
341
342 If you are shuddering, take solace from knowing you can opt out of these shenanigans:
343
344 >> t = treasure.versions.last.reify(:has_one => false) # I say no to "workarounds"!
345
346 Opting out means your `:has_one` associated objects will be the live ones, not the ones the user saw at the time. Since PaperTrail doesn't auto-restore `:has_many` associations (I can't get it to work) or `:belongs_to` (I ran out of time looking at `:has_many`), this at least makes your associations wrong consistently ;)
347
9728e315 »
2010-10-20 Automatically restore has_one associations.
348
349
f65cd0f7 »
2010-07-05 Add info and tests for has_many :through.
350 ## Has-Many-Through Associations
351
352 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:
353
354 Given these models:
355
356 class Book < ActiveRecord::Base
357 has_many :authorships, :dependent => :destroy
358 has_many :authors, :through => :authorships, :source => :person
359 has_paper_trail
360 end
361
362 class Authorship < ActiveRecord::Base
363 belongs_to :book
364 belongs_to :person
365 has_paper_trail # NOTE
366 end
367
368 class Person < ActiveRecord::Base
369 has_many :authorships, :dependent => :destroy
370 has_many :books, :through => :authorships
371 has_paper_trail
372 end
373
374 Then each of the following will store authorship versions:
375
376 >> @book.authors << @dostoyevsky
377 >> @book.authors.create :name => 'Tolstoy'
378 >> @book.authorships.last.destroy
379 >> @book.authorships.clear
380
381 But none of these will:
382
383 >> @book.authors.delete @tolstoy
384 >> @book.author_ids = [@solzhenistyn.id, @dostoyevsky.id]
385 >> @book.authors = []
386
312ff243 »
2010-10-28 Update contributors. Inline the monkey patch.
387 Having said that, you can apparently get all these working (I haven't tested it myself) with this [monkey patch](http://stackoverflow.com/questions/2381033/how-to-create-a-full-audit-log-in-rails-for-every-table/2381411#2381411):
388
389 # In config/initializers/core_extensions.rb or lib/core_extensions.rb
390 ActiveRecord::Associations::HasManyThroughAssociation.class_eval do
391 def delete_records(records)
392 klass = @reflection.through_reflection.klass
393 records.each do |associate|
394 klass.destroy_all(construct_join_attributes(associate))
395 end
396 end
397 end
398
399 The difference is the call to `destroy_all` instead of `delete_all` in [the original](http://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/has_many_through_association.rb#L76-81).
400
636945b7 »
2010-09-03 Add comment on association delete.
401
f65cd0f7 »
2010-07-05 Add info and tests for has_many :through.
402 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.
403
404
55185cd4 »
2010-01-06 Store user-defined metadata.
405 ## Storing metadata
406
3036aa75 »
2010-03-19 Store controller info. Allow other current_user methods.
407 You can store arbitrary model-level metadata alongside each version like this:
55185cd4 »
2010-01-06 Store user-defined metadata.
408
409 class Article < ActiveRecord::Base
410 belongs_to :author
0f085d19 »
2011-02-08 Add note about symbolds in the meta hash.
411 has_paper_trail :meta => { :author_id => Proc.new { |article| article.author_id },
412 :word_count => :count_words,
413 :answer => 42 }
414 def count_words
415 153
416 end
55185cd4 »
2010-01-06 Store user-defined metadata.
417 end
418
419 PaperTrail will call your proc with the current article and store the result in the `author_id` column of the `versions` table. (Remember to add your metadata columns to the table.)
420
421 Why would you do this? In this example, `author_id` is an attribute of `Article` and PaperTrail will store it anyway in serialized (YAML) form in the `object` column of the `version` record. But let's say you wanted to pull out all versions for a particular author; without the metadata you would have to deserialize (reify) each `version` object to see if belonged to the author in question. Clearly this is inefficient. Using the metadata you can find just those versions you want:
422
423 Version.all(:conditions => ['author_id = ?', author_id])
424
0f085d19 »
2011-02-08 Add note about symbolds in the meta hash.
425 Note you can pass a symbol as a value in the `meta` hash to signal a method to call.
426
3036aa75 »
2010-03-19 Store controller info. Allow other current_user methods.
427 You can also store any information you like from your controller. Just override the `info_for_paper_trail` method in your controller to return a hash whose keys correspond to columns in your `versions` table. E.g.:
428
429 class ApplicationController
430 def info_for_paper_trail
431 { :ip => request.remote_ip, :user_agent => request.user_agent }
432 end
433 end
434
435 Remember to add those extra columns to your `versions` table ;)
436
55185cd4 »
2010-01-06 Store user-defined metadata.
437
4aa1c989 »
2010-06-23 Add info on diffing.
438 ## Diffing Versions
439
e0eb4f2a »
2010-06-23 Remove redundant text.
440 When you're storing every version of an object, as PaperTrail lets you do, you're almost certainly going to want to diff those versions against each other. However I haven't built a diff method into PaperTrail because I think diffing is best left to dedicated libraries, and also it's hard to come up with a diff method to suit all the use cases.
4aa1c989 »
2010-06-23 Add info on diffing.
441
442 You might be surprised that PaperTrail doesn't use diffs internally anyway. When I designed PaperTrail I wanted simplicity and robustness so I decided to make each version of an object self-contained. A version stores all of its object's data, not a diff from the previous version.
443
444 So instead here are some specialised diffing libraries which you can use on top of PaperTrail.
445
446 For diffing two strings:
447
448 * [htmldiff](http://github.com/myobie/htmldiff): expects but doesn't require HTML input and produces HTML output. Works very well but slows down significantly on large (e.g. 5,000 word) inputs.
449 * [differ](http://github.com/pvande/differ): expects plain text input and produces plain text/coloured/HTML/any output. Can do character-wise, word-wise, line-wise, or arbitrary-boundary-string-wise diffs. Works very well on non-HTML input.
450 * [diff-lcs](http://github.com/halostatue/ruwiki/tree/master/diff-lcs/trunk): old-school, line-wise diffs.
451
452 For diffing two ActiveRecord objects:
453
454 * [Jeremy Weiskotten's PaperTrail fork](http://github.com/jeremyw/paper_trail/blob/master/lib/paper_trail/has_paper_trail.rb#L151-156): uses ActiveSupport's diff to return an array of hashes of the changes.
455 * [activerecord-diff](http://github.com/tim/activerecord-diff): rather like ActiveRecord::Dirty but also allows you to specify which columns to compare.
456
457
e9a8648c »
2009-05-27 First commit.
458 ## Turning PaperTrail Off/On
459
4f4f8145 »
2010-03-19 Global enable/disable for PaperTrail.
460 Sometimes you don't want to store changes. Perhaps you are only interested in changes made by your users and don't need to store changes you make yourself in, say, a migration -- or when testing your application.
e9a8648c »
2009-05-27 First commit.
461
4f4f8145 »
2010-03-19 Global enable/disable for PaperTrail.
462 If you are about change some widgets and you don't want a paper trail of your changes, you can turn PaperTrail off like this:
e9a8648c »
2009-05-27 First commit.
463
464 >> Widget.paper_trail_off
465
466 And on again like this:
467
468 >> Widget.paper_trail_on
469
4f4f8145 »
2010-03-19 Global enable/disable for PaperTrail.
470 You can also disable PaperTrail for all models:
471
472 >> PaperTrail.enabled = false
473
474 For example, you might want to disable PaperTrail in your Rails application's test environment to speed up your tests. This will do it:
475
476 # in config/environments/test.rb
477 config.after_initialize do
478 PaperTrail.enabled = false
479 end
480
481 If you disable PaperTrail in your test environment but want to enable it for specific tests, you can add a helper like this to your test helper:
482
483 # in test/test_helper.rb
484 def with_versioning
485 was_enabled = PaperTrail.enabled?
486 PaperTrail.enabled = true
487 begin
488 yield
489 ensure
490 PaperTrail.enabled = was_enabled
491 end
492 end
493
494 And then use it in your tests like this:
495
496 test "something that needs versioning" do
497 with_versioning do
498 # your test
499 end
500 end
501
e9a8648c »
2009-05-27 First commit.
502
6b5c8e1c »
2010-06-23 Add info on deleting old versions.
503 ## Deleting Old Versions
504
505 Over time your `versions` table will grow to an unwieldy size. Because each version is self-contained (see the Diffing section above for more) you can simply delete any records you don't want any more. For example:
506
507 sql> delete from versions where created_at < 2010-06-01;
508
509 >> Version.delete_all ["created_at < ?", 1.week.ago]
510
511
e9a8648c »
2009-05-27 First commit.
512 ## Installation
513
ba0d38c7 »
2010-10-11 Updated installation instructions for Rails 3.
514 ### Rails 3
515
516 1. Install PaperTrail as a gem via your `Gemfile`:
517
842e702b »
2011-02-08 Add Rails 3 / 2.3 instructions to README.
518 `gem 'paper_trail', '~> 2'`
ba0d38c7 »
2010-10-11 Updated installation instructions for Rails 3.
519
520 2. Generate a migration which will add a `versions` table to your database.
521
581ca47b »
2011-03-04 Update installation instructions.
522 `bundle exec rails generate paper_trail:install`
ba0d38c7 »
2010-10-11 Updated installation instructions for Rails 3.
523
524 3. Run the migration.
525
55a31e54 »
2011-02-09 Add 'bundle exec' to installation instructions.
526 `bundle exec rake db:migrate`
ba0d38c7 »
2010-10-11 Updated installation instructions for Rails 3.
527
528 4. Add `has_paper_trail` to the models you want to track.
529
530 ### Rails 2
531
2defd7cf »
2011-02-09 Tweak README about differences between Rails 3 and 2.3
532 Please see the `rails2` branch.
e9a8648c »
2009-05-27 First commit.
533
534
53d17589 »
2009-05-27 Note about the tests.
535 ## Testing
536
bd1877ca »
2010-10-15 Use Bundler to manage dependencies.
537 PaperTrail uses Bundler to manage its dependencies (in development and testing). You can run the tests with `bundle exec rake test`. (You may need to `bundle install` first.)
53d17589 »
2009-05-27 Note about the tests.
538
539
28f05c43 »
2010-02-23 Link up Linx magazine article.
540 ## Articles
541
542 [Keep a Paper Trail with PaperTrail](http://www.linux-mag.com/id/7528), Linux Magazine, 16th September 2009.
543
544
4da196ab »
2009-06-23 Expanded README.
545 ## Problems
546
547 Please use GitHub's [issue tracker](http://github.com/airblade/paper_trail/issues).
548
549
94c28e5a »
2009-11-23 Updated section on tests and added Contributors to README.
550 ## Contributors
551
552 Many thanks to:
553
554 * [Zachery Hostens](http://github.com/zacheryph)
3a4187b5 »
2010-02-18 Describe version_at in README. Add JW as contributor.
555 * [Jeremy Weiskotten](http://github.com/jeremyw)
9332ff25 »
2010-03-19 Make PaperTrail threadsafe.
556 * [Phan Le](http://github.com/revo)
557 * [jdrucza](http://github.com/jdrucza)
cd923926 »
2010-10-11 Update contributors.
558 * [conickal](http://github.com/conickal)
312ff243 »
2010-10-28 Update contributors. Inline the monkey patch.
559 * [Thibaud Guillaume-Gentil](http://github.com/thibaudgg)
560 * Danny Trelogan
5db477e0 »
2010-10-28 Update contributors.
561 * [Mikl Kurkov](http://github.com/mkurkov)
8a1fd653 »
2010-11-19 Update contributors.
562 * [Franco Catena](https://github.com/francocatena)
e69a3ae5 »
2011-02-21 Update contributors.
563 * [Emmanuel Gomez](https://github.com/emmanuel)
64fa2cbf »
2011-02-25 Update contributors.
564 * [Matthew MacLeod](https://github.com/mattmacleod)
94c28e5a »
2009-11-23 Updated section on tests and added Contributors to README.
565
566
e9a8648c »
2009-05-27 First commit.
567 ## Inspirations
568
569 * [Simply Versioned](http://github.com/github/simply_versioned)
570 * [Acts As Audited](http://github.com/collectiveidea/acts_as_audited)
571
572
573 ## Intellectual Property
574
aa5454bf »
2011-02-09 Update copyright year.
575 Copyright (c) 2011 Andy Stewart (boss@airbladesoftware.com).
e9a8648c »
2009-05-27 First commit.
576 Released under the MIT licence.
Something went wrong with that request. Please try again.