rtiss_acts_as_versioned 0.6.2

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.
@@ -0,0 +1,625 @@
1
+ # -*- encoding : utf-8 -*-
2
+ # Copyright (c) 2005 Rick Olson
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ VERSION = '0.6.2'
24
+
25
+ module ActiveRecord #:nodoc:
26
+ module Acts #:nodoc:
27
+ # Specify this act if you want to save a copy of the row in a versioned table. This assumes there is a
28
+ # versioned table ready and that your model has a version field. This works with optimistic locking if the lock_version
29
+ # column is present as well.
30
+ #
31
+ # The class for the versioned model is derived the first time it is seen. Therefore, if you change your database schema you have to restart
32
+ # your container for the changes to be reflected. In development mode this usually means restarting WEBrick.
33
+ #
34
+ # class Page < ActiveRecord::Base
35
+ # # assumes pages_versions table
36
+ # acts_as_versioned
37
+ # end
38
+ #
39
+ # Example:
40
+ #
41
+ # page = Page.create(:title => 'hello world!')
42
+ # page.version # => 1
43
+ #
44
+ # page.title = 'hello world'
45
+ # page.save
46
+ # page.version # => 2
47
+ # page.versions.size # => 2
48
+ #
49
+ # page.revert_to(1) # using version number
50
+ # page.title # => 'hello world!'
51
+ #
52
+ # page.revert_to(page.versions.last) # using versioned instance
53
+ # page.title # => 'hello world'
54
+ #
55
+ # page.versions.earliest # efficient query to find the first version
56
+ # page.versions.latest # efficient query to find the most recently created version
57
+ #
58
+ #
59
+ # Simple Queries to page between versions
60
+ #
61
+ # page.versions.before(version)
62
+ # page.versions.after(version)
63
+ #
64
+ # Access the previous/next versions from the versioned model itself
65
+ #
66
+ # version = page.versions.latest
67
+ # version.previous # go back one version
68
+ # version.next # go forward one version
69
+ #
70
+ # See ActiveRecord::Acts::Versioned::ClassMethods#acts_as_versioned for configuration options
71
+ module Versioned
72
+ CALLBACKS = [:set_new_version, :save_version, :save_version?]
73
+ def self.included(base) # :nodoc:
74
+ base.extend ClassMethods
75
+ end
76
+
77
+ module ClassMethods
78
+ # == Configuration options
79
+ #
80
+ # * <tt>class_name</tt> - versioned model class name (default: PageVersion in the above example)
81
+ # * <tt>table_name</tt> - versioned model table name (default: page_versions in the above example)
82
+ # * <tt>foreign_key</tt> - foreign key used to relate the versioned model to the original model (default: page_id in the above example)
83
+ # * <tt>inheritance_column</tt> - name of the column to save the model's inheritance_column value for STI. (default: versioned_type)
84
+ # * <tt>version_column</tt> - name of the column in the model that keeps the version number (default: version)
85
+ # * <tt>sequence_name</tt> - name of the custom sequence to be used by the versioned model.
86
+ # * <tt>limit</tt> - number of revisions to keep, defaults to unlimited
87
+ # * <tt>if</tt> - symbol of method to check before saving a new version. If this method returns false, a new version is not saved.
88
+ # For finer control, pass either a Proc or modify Model#version_condition_met?
89
+ #
90
+ # acts_as_versioned :if => Proc.new { |auction| !auction.expired? }
91
+ #
92
+ # or...
93
+ #
94
+ # class Auction
95
+ # def version_condition_met? # totally bypasses the <tt>:if</tt> option
96
+ # !expired?
97
+ # end
98
+ # end
99
+ #
100
+ # * <tt>if_changed</tt> - Simple way of specifying attributes that are required to be changed before saving a model. This takes
101
+ # either a symbol or array of symbols.
102
+ #
103
+ # * <tt>extend</tt> - Lets you specify a module to be mixed in both the original and versioned models. You can also just pass a block
104
+ # to create an anonymous mixin:
105
+ #
106
+ # class Auction
107
+ # acts_as_versioned do
108
+ # def started?
109
+ # !started_at.nil?
110
+ # end
111
+ # end
112
+ # end
113
+ #
114
+ # or...
115
+ #
116
+ # module AuctionExtension
117
+ # def started?
118
+ # !started_at.nil?
119
+ # end
120
+ # end
121
+ # class Auction
122
+ # acts_as_versioned :extend => AuctionExtension
123
+ # end
124
+ #
125
+ # Example code:
126
+ #
127
+ # @auction = Auction.find(1)
128
+ # @auction.started?
129
+ # @auction.versions.first.started?
130
+ #
131
+ # == Database Schema
132
+ #
133
+ # The model that you're versioning needs to have a 'version' attribute. The model is versioned
134
+ # into a table called #{model}_versions where the model name is singlular. The _versions table should
135
+ # contain all the fields you want versioned, the same version column, and a #{model}_id foreign key field.
136
+ #
137
+ # A lock_version field is also accepted if your model uses Optimistic Locking. If your table uses Single Table inheritance,
138
+ # then that field is reflected in the versioned model as 'versioned_type' by default.
139
+ #
140
+ # Acts_as_versioned comes prepared with the ActiveRecord::Acts::Versioned::ActMethods::ClassMethods#create_versioned_table
141
+ # method, perfect for a migration. It will also create the version column if the main model does not already have it.
142
+ #
143
+ # class AddVersions < ActiveRecord::Migration
144
+ # def self.up
145
+ # # create_versioned_table takes the same options hash
146
+ # # that create_table does
147
+ # Post.create_versioned_table
148
+ # end
149
+ #
150
+ # def self.down
151
+ # Post.drop_versioned_table
152
+ # end
153
+ # end
154
+ #
155
+ # == Changing What Fields Are Versioned
156
+ #
157
+ # By default, acts_as_versioned will version all but these fields:
158
+ #
159
+ # [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column]
160
+ #
161
+ # You can add or change those by modifying #non_versioned_columns. Note that this takes strings and not symbols.
162
+ #
163
+ # class Post < ActiveRecord::Base
164
+ # acts_as_versioned
165
+ # self.non_versioned_columns << 'comments_count'
166
+ # end
167
+ #
168
+ def acts_as_versioned(options = {}, &extension)
169
+ # don't allow multiple calls
170
+ return if self.included_modules.include?(ActiveRecord::Acts::Versioned::ActMethods)
171
+
172
+ send :include, ActiveRecord::Acts::Versioned::ActMethods
173
+
174
+ cattr_accessor :versioned_class_name, :versioned_foreign_key, :versioned_table_name, :versioned_inheritance_column,
175
+ :version_column, :max_version_limit, :track_altered_attributes, :version_condition, :version_sequence_name, :non_versioned_columns,
176
+ :version_association_options, :version_if_changed, :deleted_in_original_table_flag, :record_restored_flag
177
+
178
+ self.versioned_class_name = options[:class_name] || "Version"
179
+ self.versioned_foreign_key = options[:foreign_key] || self.to_s.foreign_key
180
+ self.versioned_table_name = options[:table_name] || if self.table_name then "#{table_name}_h" else "#{table_name_prefix}#{base_class.name.demodulize.underscore}_h#{table_name_suffix}" end
181
+
182
+ self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}"
183
+ self.version_column = options[:version_column] || 'version'
184
+ self.deleted_in_original_table_flag = options[:deleted_in_original_table_flag] || 'deleted_in_original_table'
185
+ self.record_restored_flag = options[:record_restored_flag] || 'record_restored'
186
+ self.version_sequence_name = options[:sequence_name]
187
+ self.max_version_limit = options[:limit].to_i
188
+ self.version_condition = options[:if] || true
189
+ self.non_versioned_columns = [self.primary_key, inheritance_column, self.version_column, 'lock_version', versioned_inheritance_column] + options[:non_versioned_columns].to_a.map(&:to_s)
190
+ self.version_association_options = {
191
+ :class_name => "#{self.to_s}::#{versioned_class_name}",
192
+ :foreign_key => versioned_foreign_key
193
+ }.merge(options[:association_options] || {})
194
+
195
+ if block_given?
196
+ extension_module_name = "#{versioned_class_name}Extension"
197
+ silence_warnings do
198
+ self.const_set(extension_module_name, Module.new(&extension))
199
+ end
200
+
201
+ options[:extend] = self.const_get(extension_module_name)
202
+ end
203
+
204
+ class_eval <<-CLASS_METHODS
205
+ has_many :versions, version_association_options do
206
+ # finds earliest version of this record
207
+ def earliest
208
+ @earliest ||= find(:first, :order => '#{version_column}')
209
+ end
210
+
211
+ # find latest version of this record
212
+ def latest
213
+ @latest ||= find(:first, :order => '#{version_column} desc')
214
+ end
215
+ end
216
+ before_save :set_new_version
217
+ after_save :save_version
218
+ after_save :clear_old_versions
219
+ after_destroy :set_deleted_flag
220
+
221
+ unless options[:if_changed].nil?
222
+ self.track_altered_attributes = true
223
+ options[:if_changed] = [options[:if_changed]] unless options[:if_changed].is_a?(Array)
224
+ self.version_if_changed = options[:if_changed].map(&:to_s)
225
+ end
226
+
227
+ include options[:extend] if options[:extend].is_a?(Module)
228
+ CLASS_METHODS
229
+
230
+ # create the dynamic versioned model
231
+ const_set(versioned_class_name, Class.new(ActiveRecord::Base)).class_eval do
232
+ def self.reloadable? ; false ; end
233
+ # find first version before the given version
234
+ def self.before(version)
235
+ find :first, :order => 'version desc',
236
+ :conditions => ["#{original_class.versioned_foreign_key} = ? and version < ?", version.send(original_class.versioned_foreign_key), version.version]
237
+ end
238
+
239
+ # find first version after the given version.
240
+ def self.after(version)
241
+ find :first, :order => 'version',
242
+ :conditions => ["#{original_class.versioned_foreign_key} = ? and version > ?", version.send(original_class.versioned_foreign_key), version.version]
243
+ end
244
+
245
+ def previous
246
+ self.class.before(self)
247
+ end
248
+
249
+ def next
250
+ self.class.after(self)
251
+ end
252
+
253
+ def versions_count
254
+ page.version # TODO: ?!
255
+ end
256
+
257
+ def restore(perform_validation = true)
258
+ id = self.send(self.original_class.versioned_foreign_key)
259
+ if self.original_class.exists?(id)
260
+ raise RuntimeError.new("Record exists in restore, id = #{id} class = #{self.class.name}")
261
+ end
262
+
263
+ version_hash = self.attributes
264
+ version_hash.delete "id"
265
+ version_hash.delete self.original_class.deleted_in_original_table_flag.to_s
266
+ version_hash.delete self.original_class.record_restored_flag.to_s
267
+ version_hash.delete self.original_class.versioned_foreign_key.to_s
268
+
269
+ restored_record = self.original_class.new(version_hash)
270
+ restored_record.id = id
271
+ if restored_record.respond_to? :updated_at=
272
+ restored_record.updated_at = Time.now
273
+ end
274
+ unless restored_record.save_without_revision(perform_validation)
275
+ raise RuntimeError.new("Couldn't restore the record, id = #{id} class = #{self.class.name}")
276
+ end
277
+
278
+ new_version = clone
279
+ new_version.version += 1
280
+ new_version.send("#{self.original_class.deleted_in_original_table_flag}=", false)
281
+ new_version.send("#{self.original_class.record_restored_flag}=", true)
282
+ if new_version.respond_to? :updated_at=
283
+ new_version.updated_at = Time.now
284
+ end
285
+ new_version.save!
286
+ end
287
+
288
+ def original_record_exists?
289
+ original_class.exists?(self.send original_class.versioned_foreign_key)
290
+ end
291
+ end
292
+
293
+ versioned_class.cattr_accessor :original_class
294
+ versioned_class.original_class = self
295
+ versioned_class.set_table_name versioned_table_name
296
+ versioned_class.belongs_to self.to_s.demodulize.underscore.to_sym,
297
+ :class_name => "::#{self.to_s}",
298
+ :foreign_key => versioned_foreign_key
299
+ versioned_class.send :include, options[:extend] if options[:extend].is_a?(Module)
300
+ versioned_class.set_sequence_name version_sequence_name if version_sequence_name
301
+ end
302
+ end
303
+
304
+ module ActMethods
305
+ def self.included(base) # :nodoc:
306
+ base.extend ClassMethods
307
+ end
308
+
309
+ # Saves a version of the model in the versioned table. This is called in the after_save callback by default
310
+ def save_version
311
+ if @saving_version
312
+ @saving_version = nil
313
+ rev = self.class.versioned_class.new
314
+ clone_versioned_model(self, rev)
315
+ rev.send("#{self.class.version_column}=", send(self.class.version_column))
316
+ rev.send("#{self.class.versioned_foreign_key}=", id)
317
+ rev.send("#{self.class.deleted_in_original_table_flag}=", false)
318
+ rev.send("#{self.class.record_restored_flag}=", false)
319
+ if rev.respond_to? :updated_at=
320
+ rev.updated_at = Time.now
321
+ end
322
+ rev.save
323
+ end
324
+ end
325
+
326
+ def set_deleted_flag
327
+ return if self.id.nil?
328
+
329
+ rev = self.class.versioned_class.new
330
+ clone_versioned_model(self, rev)
331
+ rev.send("#{self.class.version_column}=", highest_version+1)
332
+ rev.send("#{self.class.versioned_foreign_key}=", id)
333
+ rev.send("#{self.class.deleted_in_original_table_flag}=", true)
334
+ rev.send("#{self.class.record_restored_flag}=", false)
335
+ if rev.respond_to? :updated_at=
336
+ rev.updated_at = Time.now
337
+ end
338
+ rev.save
339
+ end
340
+
341
+ # Clears old revisions if a limit is set with the :limit option in <tt>acts_as_versioned</tt>.
342
+ # Override this method to set your own criteria for clearing old versions.
343
+ def clear_old_versions
344
+ return if self.class.max_version_limit == 0
345
+ excess_baggage = send(self.class.version_column).to_i - self.class.max_version_limit
346
+ if excess_baggage > 0
347
+ self.class.versioned_class.delete_all ["#{self.class.version_column} <= ? and #{self.class.versioned_foreign_key} = ?", excess_baggage, id]
348
+ end
349
+ end
350
+
351
+ # Reverts a model to a given version. Takes either a version number or an instance of the versioned model
352
+ def revert_to(version)
353
+ if version.is_a?(self.class.versioned_class)
354
+ return false unless version.send(self.class.versioned_foreign_key) == id and !version.new_record?
355
+ else
356
+ return false unless version = versions.send("find_by_#{self.class.version_column}", version)
357
+ end
358
+ self.clone_versioned_model(version, self)
359
+ send("#{self.class.version_column}=", version.send(self.class.version_column))
360
+ true
361
+ end
362
+
363
+ # Reverts a model to a given version and saves the model.
364
+ # Takes either a version number or an instance of the versioned model
365
+ def revert_to!(version)
366
+ revert_to(version) ? save_without_revision : false
367
+ end
368
+
369
+ # Temporarily turns off Optimistic Locking while saving. Used when reverting so that a new version is not created.
370
+ def save_without_revision(perform_validation = true)
371
+ ret = false
372
+ without_locking do
373
+ without_revision do
374
+ ret = save(perform_validation)
375
+ end
376
+ end
377
+ return ret
378
+ end
379
+
380
+ def save_without_revision!
381
+ without_locking do
382
+ without_revision do
383
+ save!
384
+ end
385
+ end
386
+ end
387
+
388
+ def altered?
389
+ track_altered_attributes ? (version_if_changed - changed).length < version_if_changed.length : changed?
390
+ end
391
+
392
+ # Clones a model. Used when saving a new version or reverting a model's version.
393
+ def clone_versioned_model(orig_model, new_model)
394
+ self.class.versioned_columns.each do |col|
395
+ new_model.send("#{col.name}=", orig_model.send(col.name)) if orig_model.has_attribute?(col.name)
396
+ end
397
+
398
+ if orig_model.is_a?(self.class.versioned_class)
399
+ new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column]
400
+ elsif new_model.is_a?(self.class.versioned_class)
401
+ new_model[self.class.versioned_inheritance_column] = orig_model[orig_model.class.inheritance_column]
402
+ end
403
+ end
404
+
405
+ # Checks whether a new version shall be saved or not. Calls <tt>version_condition_met?</tt> and <tt>changed?</tt>.
406
+ def save_version?
407
+ version_condition_met? && altered?
408
+ end
409
+
410
+ # Checks condition set in the :if option to check whether a revision should be created or not. Override this for
411
+ # custom version condition checking.
412
+ def version_condition_met?
413
+ case
414
+ when version_condition.is_a?(Symbol)
415
+ send(version_condition)
416
+ when version_condition.respond_to?(:call) && (version_condition.arity == 1 || version_condition.arity == -1)
417
+ version_condition.call(self)
418
+ else
419
+ version_condition
420
+ end
421
+ end
422
+
423
+ # Executes the block with the versioning callbacks disabled.
424
+ #
425
+ # @foo.without_revision do
426
+ # @foo.save
427
+ # end
428
+ #
429
+ def without_revision(&block)
430
+ self.class.without_revision(&block)
431
+ end
432
+
433
+ # Turns off optimistic locking for the duration of the block
434
+ #
435
+ # @foo.without_locking do
436
+ # @foo.save
437
+ # end
438
+ #
439
+ def without_locking(&block)
440
+ self.class.without_locking(&block)
441
+ end
442
+
443
+ def empty_callback() end #:nodoc:
444
+
445
+ def find_versions(*args)
446
+ return [] if self.id.nil?
447
+
448
+ options = args.extract_options!
449
+ version_condition = "#{self.class.versioned_foreign_key} = #{self.id}"
450
+ if options[:conditions] then
451
+ options[:conditions] += " and #{version_condition}"
452
+ else
453
+ options[:conditions] = version_condition
454
+ end
455
+ if args.first.is_a?(Symbol)
456
+ versions.find(args.first, options)
457
+ else # TODO: is_a?(Fixnum)
458
+ versions.find(options)
459
+ end
460
+ end
461
+
462
+ def find_newest_version
463
+ return nil if self.id.nil?
464
+
465
+ self.class.versioned_class.find(:first, :conditions => "#{self.class.versioned_foreign_key} = #{self.id}", :order => "version DESC")
466
+ end
467
+
468
+ def highest_version
469
+ v = find_newest_version
470
+ if v then
471
+ v.version
472
+ else
473
+ -1
474
+ end
475
+ end
476
+
477
+ def find_version(version)
478
+ return nil if self.id.nil?
479
+
480
+ ret = self.class.versioned_class.find(:first, :conditions => "#{self.class.versioned_foreign_key} = #{self.id} and version=#{version}") # TODO: version column
481
+ raise "find_version: version #{version} not found in database" unless ret
482
+ ret
483
+ end
484
+
485
+ protected
486
+ # sets the new version before saving, unless you're using optimistic locking. In that case, let it take care of the version.
487
+ def set_new_version
488
+ @saving_version = new_record? || save_version?
489
+ self.send("#{self.class.version_column}=", next_version) if new_record? || (!locking_enabled? && save_version?)
490
+ end
491
+
492
+ # Gets the next available version for the current record, or 1 for a new record
493
+ def next_version
494
+ (new_record? ? 0 : versions.calculate(:max, version_column).to_i) + 1
495
+ end
496
+
497
+ module ClassMethods
498
+ # Returns an array of columns that are versioned. See non_versioned_columns
499
+ def versioned_columns
500
+ @versioned_columns ||= columns.select { |c| !non_versioned_columns.include?(c.name) }
501
+ end
502
+
503
+ # Returns an instance of the dynamic versioned model
504
+ def versioned_class
505
+ const_get versioned_class_name
506
+ end
507
+
508
+ # Rake migration task to create the versioned table using options passed to acts_as_versioned
509
+ def create_versioned_table(create_table_options = {})
510
+ # create version column in main table if it does not exist
511
+ if !self.content_columns.find { |c| [version_column.to_s, 'lock_version'].include? c.name }
512
+ self.connection.add_column table_name, version_column, :integer
513
+ self.reset_column_information
514
+ end
515
+
516
+ return if connection.table_exists?(versioned_table_name)
517
+
518
+ self.connection.create_table(versioned_table_name, create_table_options) do |t|
519
+ t.column versioned_foreign_key, :integer
520
+ t.column version_column, :integer
521
+ t.column deleted_in_original_table_flag, :boolean, :default => false
522
+ t.column record_restored_flag, :boolean, :default => false
523
+ end
524
+
525
+ self.versioned_columns.each do |col|
526
+ self.connection.add_column versioned_table_name, col.name, col.type,
527
+ :limit => col.limit,
528
+ :default => col.default,
529
+ :scale => col.scale,
530
+ :precision => col.precision
531
+ end
532
+
533
+ if type_col = self.columns_hash[inheritance_column]
534
+ self.connection.add_column versioned_table_name, versioned_inheritance_column, type_col.type,
535
+ :limit => type_col.limit,
536
+ :default => type_col.default,
537
+ :scale => type_col.scale,
538
+ :precision => type_col.precision
539
+ end
540
+
541
+ #self.connection.add_index versioned_table_name, versioned_foreign_key
542
+ end
543
+
544
+ # Rake migration task to drop the versioned table
545
+ def drop_versioned_table
546
+ self.connection.drop_table versioned_table_name
547
+ end
548
+
549
+ def restore_deleted(id)
550
+ version_record = versioned_class.find(:first, :conditions => "#{versioned_foreign_key} = #{id}", :order => "version DESC")
551
+ version_record.restore
552
+ end
553
+
554
+ def restore_deleted_version(id, version)
555
+ version_record = versioned_class.find(:first, :conditions => "#{versioned_foreign_key} = #{id} and version = #{version}")
556
+ version_record.restore
557
+ end
558
+
559
+ # Executes the block with the versioning callbacks disabled.
560
+ #
561
+ # Foo.without_revision do
562
+ # @foo.save
563
+ # end
564
+ #
565
+ def without_revision(&block)
566
+ class_eval do
567
+ CALLBACKS.each do |attr_name|
568
+ alias_method "orig_#{attr_name}".to_sym, attr_name
569
+ alias_method attr_name, :empty_callback
570
+ end
571
+ end
572
+ block.call
573
+ ensure
574
+ class_eval do
575
+ CALLBACKS.each do |attr_name|
576
+ alias_method attr_name, "orig_#{attr_name}".to_sym
577
+ end
578
+ end
579
+ end
580
+
581
+ # Turns off optimistic locking for the duration of the block
582
+ #
583
+ # Foo.without_locking do
584
+ # @foo.save
585
+ # end
586
+ #
587
+ def without_locking(&block)
588
+ current = ActiveRecord::Base.lock_optimistically
589
+ ActiveRecord::Base.lock_optimistically = false if current
590
+ begin
591
+ block.call
592
+ ensure
593
+ ActiveRecord::Base.lock_optimistically = true if current
594
+ end
595
+ end
596
+ end
597
+ end
598
+ end
599
+ end
600
+ end
601
+
602
+ # TISS extension: do not pull this.
603
+ # TODO: Move to TISS app (initializer)
604
+ module ActiveRecord #:nodoc:
605
+ module ConnectionAdapters #:nodoc:
606
+ class TableDefinition
607
+ ## Erzeugt 4 Spalten created_at, updated_at, version, mutator_id die in
608
+ ## jeder Daten-Tabelle notwendig sind. Verwendung:
609
+ ## create_table :adresse do |t|
610
+ ## t.standard_spalten
611
+ ## t.string strasse, :size=>120
612
+ ## t.string plz, :size=>4
613
+ ## end
614
+ def standard_spalten
615
+ column(:created_at, :datetime)
616
+ column(:updated_at, :datetime)
617
+ column(:version, :integer, :default=>1)
618
+ column(:mutator_id, :integer, :default=>0)
619
+ end
620
+ end
621
+ end
622
+ end
623
+
624
+
625
+ ActiveRecord::Base.send :include, ActiveRecord::Acts::Versioned