kb-acts_as_revisable 1.0.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.
@@ -0,0 +1,491 @@
1
+ module WithoutScope
2
+ module ActsAsRevisable
3
+
4
+ # This module is mixed into the revision classes.
5
+ #
6
+ # ==== Callbacks
7
+ #
8
+ # * +before_revise+ is called before the record is revised.
9
+ # * +after_revise+ is called after the record is revised.
10
+ # * +before_revert+ is called before the record is reverted.
11
+ # * +after_revert+ is called after the record is reverted.
12
+ # * +before_changeset+ is called before a changeset block is called.
13
+ # * +after_changeset+ is called after a changeset block is called.
14
+ # * +after_branch_created+ is called on the new revisable instance
15
+ # created by branching after it's been created.
16
+ module Revisable
17
+ def self.included(base) #:nodoc:
18
+ base.send(:extend, ClassMethods)
19
+
20
+ class << base
21
+ attr_accessor :revisable_revision_class, :revisable_columns
22
+ end
23
+
24
+ base.class_inheritable_hash :revisable_shared_objects
25
+ base.revisable_shared_objects = {}
26
+
27
+ base.instance_eval do
28
+ attr_accessor :revisable_new_params, :revisable_revision
29
+
30
+ define_callbacks :before_revise, :after_revise, :before_revert, :after_revert, :before_changeset, :after_changeset, :after_branch_created
31
+
32
+ before_create :before_revisable_create
33
+ before_update :before_revisable_update
34
+ after_update :after_revisable_update
35
+ after_save :clear_revisable_shared_objects!, :unless => :is_reverting?
36
+
37
+ default_scope :conditions => {:revisable_is_current => true}
38
+
39
+ [:revisions, revisions_association_name.to_sym].each do |assoc|
40
+ has_many assoc, (revisable_options.revision_association_options || {}).merge({:class_name => revision_class_name, :foreign_key => :revisable_original_id, :order => "#{quoted_table_name}.#{connection.quote_column_name(:revisable_number)} DESC", :dependent => :destroy})
41
+ end
42
+ end
43
+
44
+ if !Object.const_defined?(base.revision_class_name) && base.revisable_options.generate_revision_class?
45
+ Object.const_set(base.revision_class_name, Class.new(ActiveRecord::Base)).class_eval do
46
+ acts_as_revision
47
+ end
48
+ end
49
+ end
50
+
51
+ # Finds a specific revision of self.
52
+ #
53
+ # The +by+ parameter can be a revision_class instance,
54
+ # the symbols :first, :previous or :last, a Time instance
55
+ # or an Integer.
56
+ #
57
+ # When passed a revision_class instance, this method
58
+ # simply returns it. This is used primarily by revert_to!.
59
+ #
60
+ # When passed :first it returns the first revision created.
61
+ #
62
+ # When passed :previous or :last it returns the last revision
63
+ # created.
64
+ #
65
+ # When passed a Time instance it returns the revision that
66
+ # was the current record at the given time.
67
+ #
68
+ # When passed an Integer it returns the revision with that
69
+ # revision_number.
70
+ def find_revision(by)
71
+ by = Integer(by) if by.is_a?(String) && by.match(/[0-9]+/)
72
+
73
+ case by
74
+ when self.class
75
+ by
76
+ when self.class.revision_class
77
+ by
78
+ when :first
79
+ revisions.last
80
+ when :previous
81
+ revisions.first
82
+ when Time
83
+ revisions.find(:first, :conditions => ["? >= ? and ? <= ?", :revisable_revised_at, by, :revisable_current_at, by])
84
+ when self.revisable_number
85
+ self
86
+ else
87
+ revisions.find_by_revisable_number(by)
88
+ end
89
+ end
90
+
91
+ # Returns a revisable_class instance initialized with the record
92
+ # found using find_revision.
93
+ #
94
+ # The +what+ parameter is simply passed to find_revision and the
95
+ # returned record forms the basis of the reverted record.
96
+ #
97
+ # ==== Callbacks
98
+ #
99
+ # * +before_revert+ is called before the record is reverted.
100
+ # * +after_revert+ is called after the record is reverted.
101
+ #
102
+ # If :without_revision => true has not been passed the
103
+ # following callbacks are also called:
104
+ #
105
+ # * +before_revise+ is called before the record is revised.
106
+ # * +after_revise+ is called after the record is revised.
107
+ def revert_to(what, *args, &block) #:yields:
108
+ is_reverting!
109
+
110
+ unless run_callbacks(:before_revert) { |r, o| r == false}
111
+ raise ActiveRecord::RecordNotSaved
112
+ end
113
+
114
+ options = args.extract_options!
115
+
116
+ rev = find_revision(what)
117
+ self.reverting_to, self.reverting_from = rev, self
118
+
119
+ unless rev.run_callbacks(:before_restore) { |r, o| r == false}
120
+ raise ActiveRecord::RecordNotSaved
121
+ end
122
+
123
+ self.class.column_names.each do |col|
124
+ next unless self.class.revisable_should_clone_column? col
125
+ self[col] = rev[col]
126
+ end
127
+
128
+ self.no_revision! if options.delete :without_revision
129
+ self.revisable_new_params = options
130
+
131
+ yield(self) if block_given?
132
+ rev.run_callbacks(:after_restore)
133
+ run_callbacks(:after_revert)
134
+ self
135
+ ensure
136
+ is_reverting!(false)
137
+ clear_revisable_shared_objects!
138
+ end
139
+
140
+ # Same as revert_to except it also saves the record.
141
+ def revert_to!(what, *args)
142
+ revert_to(what, *args) do
143
+ self.no_revision? ? save! : revise!
144
+ end
145
+ end
146
+
147
+ # Equivalent to:
148
+ # revert_to(:without_revision => true)
149
+ def revert_to_without_revision(*args)
150
+ options = args.extract_options!
151
+ options.update({:without_revision => true})
152
+ revert_to(*(args << options))
153
+ end
154
+
155
+ # Equivalent to:
156
+ # revert_to!(:without_revision => true)
157
+ def revert_to_without_revision!(*args)
158
+ options = args.extract_options!
159
+ options.update({:without_revision => true})
160
+ revert_to!(*(args << options))
161
+ end
162
+
163
+ # Globally sets the reverting state of this record.
164
+ def is_reverting!(val=true) #:nodoc:
165
+ set_revisable_state(:reverting, val)
166
+ end
167
+
168
+ # Returns true if the _record_ (not just this instance
169
+ # of the record) is currently being reverted.
170
+ def is_reverting?
171
+ get_revisable_state(:reverting) || false
172
+ end
173
+
174
+ # Sets whether or not to force a revision.
175
+ def force_revision!(val=true) #:nodoc:
176
+ set_revisable_state(:force_revision, val)
177
+ end
178
+
179
+ # Returns true if a revision should be forced.
180
+ def force_revision? #:nodoc:
181
+ get_revisable_state(:force_revision) || false
182
+ end
183
+
184
+ # Sets whether or not a revision should be created.
185
+ def no_revision!(val=true) #:nodoc:
186
+ set_revisable_state(:no_revision, val)
187
+ end
188
+
189
+ # Returns true if no revision should be created.
190
+ def no_revision? #:nodoc:
191
+ get_revisable_state(:no_revision) || false
192
+ end
193
+
194
+ # Force an immediate revision whether or
195
+ # not any columns have been modified.
196
+ #
197
+ # The +args+ catch-all argument is not used. It's primarily
198
+ # there to allow +revise!+ to be used directly as an association
199
+ # callback since association callbacks are passed an argument.
200
+ #
201
+ # ==== Callbacks
202
+ #
203
+ # * +before_revise+ is called before the record is revised.
204
+ # * +after_revise+ is called after the record is revised.
205
+ def revise!(*args)
206
+ return if in_revision?
207
+
208
+ begin
209
+ force_revision!
210
+ in_revision!
211
+ save!
212
+ ensure
213
+ in_revision!(false)
214
+ force_revision!(false)
215
+ end
216
+ end
217
+
218
+ # Groups statements that could trigger several revisions into
219
+ # a single revision. The revision is created once #save is called.
220
+ #
221
+ # ==== Example
222
+ #
223
+ # @project.revision_number # => 1
224
+ # @project.changeset do |project|
225
+ # # each one of the following statements would
226
+ # # normally trigger a revision
227
+ # project.update_attribute(:name, "new name")
228
+ # project.revise!
229
+ # project.revise!
230
+ # end
231
+ # @project.save
232
+ # @project.revision_number # => 2
233
+ #
234
+ # ==== Callbacks
235
+ #
236
+ # * +before_changeset+ is called before a changeset block is called.
237
+ # * +after_changeset+ is called after a changeset block is called.
238
+ def changeset(&block)
239
+ return unless block_given?
240
+
241
+ return yield(self) if in_revision?
242
+
243
+ unless run_callbacks(:before_changeset) { |r, o| r == false}
244
+ raise ActiveRecord::RecordNotSaved
245
+ end
246
+
247
+ begin
248
+ force_revision!
249
+ in_revision!
250
+
251
+ returning(yield(self)) do
252
+ run_callbacks(:after_changeset)
253
+ end
254
+ ensure
255
+ in_revision!(false)
256
+ end
257
+ end
258
+
259
+ # Same as +changeset+ except it also saves the record.
260
+ def changeset!(&block)
261
+ changeset do
262
+ block.call(self)
263
+ save!
264
+ end
265
+ end
266
+
267
+ def without_revisions!
268
+ return if in_revision? || !block_given?
269
+
270
+ begin
271
+ no_revision!
272
+ in_revision!
273
+ yield
274
+ save!
275
+ ensure
276
+ in_revision!(false)
277
+ no_revision!(false)
278
+ end
279
+ end
280
+
281
+ # acts_as_revisable's override for ActiveRecord::Base's #save!
282
+ def save!(*args) #:nodoc:
283
+ self.revisable_new_params ||= args.extract_options!
284
+ self.no_revision! if self.revisable_new_params.delete :without_revision
285
+ super
286
+ end
287
+
288
+ # acts_as_revisable's override for ActiveRecord::Base's #save
289
+ def save(*args) #:nodoc:
290
+ self.revisable_new_params ||= args.extract_options!
291
+ self.no_revision! if self.revisable_new_params.delete :without_revision
292
+ super(args)
293
+ end
294
+
295
+ # Set some defaults for a newly created +Revisable+ instance.
296
+ def before_revisable_create #:nodoc:
297
+ self[:revisable_is_current] = true
298
+ self.revision_number ||= 0
299
+ end
300
+
301
+ # Checks whether or not a +Revisable+ should be revised.
302
+ def should_revise? #:nodoc:
303
+ return false if new_record?
304
+ return true if force_revision?
305
+ return false if no_revision?
306
+ return false unless self.changed?
307
+ !(self.changed.map(&:downcase) & self.class.revisable_watch_columns).blank?
308
+ end
309
+
310
+ # Checks whether or not a revision should be stored.
311
+ # If it should be, it initialized the revision_class
312
+ # and stores it in an accessor for later saving.
313
+ def before_revisable_update #:nodoc:
314
+ return unless should_revise?
315
+ in_revision!
316
+
317
+ unless run_callbacks(:before_revise) { |r, o| r == false}
318
+ in_revision!(false)
319
+ return false
320
+ end
321
+
322
+ self.revisable_revision = self.to_revision
323
+ end
324
+
325
+ # Checks if an initialized revision_class has been stored
326
+ # in the accessor. If it has been, this instance is saved.
327
+ def after_revisable_update #:nodoc:
328
+ if no_revision? # check and see if no_revision! was called in a callback
329
+ self.revisable_revision = nil
330
+ return true
331
+ elsif self.revisable_revision
332
+ if self.class.revision_class.respond_to?(:without_stamps)
333
+ self.class.revision_class.without_stamps do
334
+ self.revisable_revision.save
335
+ end
336
+ else
337
+ self.revisable_revision.save
338
+ end
339
+ revisions.reload
340
+ run_callbacks(:after_revise)
341
+ end
342
+ in_revision!(false)
343
+ force_revision!(false)
344
+ true
345
+ end
346
+
347
+ # Returns true if the _record_ (not just this instance
348
+ # of the record) is currently being revised.
349
+ def in_revision?
350
+ get_revisable_state(:revision)
351
+ end
352
+
353
+ # Manages the internal state of a +Revisable+ controlling
354
+ # whether or not a record is being revised. This works across
355
+ # instances and is keyed on primary_key.
356
+ def in_revision!(val=true) #:nodoc:
357
+ set_revisable_state(:revision, val)
358
+ end
359
+
360
+ # This returns a new +Revision+ instance with all the appropriate
361
+ # values initialized.
362
+ def to_revision #:nodoc:
363
+ rev = self.class.revision_class.new(self.revisable_new_params)
364
+
365
+ rev.revisable_original_id = self.id
366
+
367
+ new_revision_number = revisions.maximum(:revisable_number) + 1 rescue self.revision_number
368
+ rev.revision_number = new_revision_number
369
+ self.revision_number = new_revision_number + 1
370
+
371
+ self.class.column_names.each do |col|
372
+ next unless self.class.revisable_should_clone_column? col
373
+ val = self.send("#{col}_changed?") ? self.send("#{col}_was") : self.send(col)
374
+ rev.send("#{col}=", val)
375
+ end
376
+
377
+ self.revisable_new_params = nil
378
+
379
+ rev
380
+ end
381
+
382
+ # This returns
383
+ def current_revision
384
+ self
385
+ end
386
+
387
+ def for_revision
388
+ key = self.read_attribute(self.class.primary_key)
389
+ self.class.revisable_shared_objects[key] ||= {}
390
+ end
391
+
392
+ def reverting_to
393
+ for_revision[:reverting_to]
394
+ end
395
+
396
+ def reverting_to=(val)
397
+ for_revision[:reverting_to] = val
398
+ end
399
+
400
+ def reverting_from
401
+ for_revision[:reverting_from]
402
+ end
403
+
404
+ def reverting_from=(val)
405
+ for_revision[:reverting_from] = val
406
+ end
407
+
408
+ def clear_revisable_shared_objects!
409
+ key = self.read_attribute(self.class.primary_key)
410
+ self.class.revisable_shared_objects.delete(key)
411
+ end
412
+
413
+ module ClassMethods
414
+ # acts_as_revisable's override for with_scope that allows for
415
+ # including revisions in the scope.
416
+ #
417
+ # ==== Example
418
+ #
419
+ # with_scope(:with_revisions => true) do
420
+ # ...
421
+ # end
422
+ def with_scope(*args, &block) #:nodoc:
423
+ options = (args.grep(Hash).first || {})[:find]
424
+
425
+ if options && options.delete(:with_revisions)
426
+ with_exclusive_scope do
427
+ super(*args, &block)
428
+ end
429
+ else
430
+ super(*args, &block)
431
+ end
432
+ end
433
+
434
+ # acts_as_revisable's override for find that allows for
435
+ # including revisions in the find.
436
+ #
437
+ # ==== Example
438
+ #
439
+ # find(:all, :with_revisions => true)
440
+ def find(*args) #:nodoc:
441
+ options = args.grep(Hash).first
442
+
443
+ if options && options.delete(:with_revisions)
444
+ with_exclusive_scope do
445
+ super(*args)
446
+ end
447
+ else
448
+ super(*args)
449
+ end
450
+ end
451
+
452
+ # Returns the +revision_class_name+ as configured in
453
+ # +acts_as_revisable+.
454
+ def revision_class_name #:nodoc:
455
+ self.revisable_options.revision_class_name || "#{self.class_name}Revision"
456
+ end
457
+
458
+ # Returns the actual +Revision+ class based on the
459
+ # #revision_class_name.
460
+ def revision_class #:nodoc:
461
+ self.revisable_revision_class ||= self.revision_class_name.constantize
462
+ end
463
+
464
+ # Returns the revisable_class which in this case is simply +self+.
465
+ def revisable_class #:nodoc:
466
+ self
467
+ end
468
+
469
+ # Returns the name of the association acts_as_revisable
470
+ # creates.
471
+ def revisions_association_name #:nodoc:
472
+ revision_class_name.pluralize.underscore
473
+ end
474
+
475
+ # Returns an Array of the columns that are watched for changes.
476
+ def revisable_watch_columns #:nodoc:
477
+ return self.revisable_columns unless self.revisable_columns.blank?
478
+ return self.revisable_columns ||= [] if self.revisable_options.except == :all
479
+ return self.revisable_columns ||= [self.revisable_options.only].flatten.map(&:to_s).map(&:downcase) unless self.revisable_options.only.blank?
480
+
481
+ except = [self.revisable_options.except].flatten || []
482
+ except += REVISABLE_SYSTEM_COLUMNS
483
+ except += REVISABLE_UNREVISABLE_COLUMNS
484
+ except.uniq!
485
+
486
+ self.revisable_columns ||= (column_names - except.map(&:to_s)).flatten.map(&:downcase)
487
+ end
488
+ end
489
+ end
490
+ end
491
+ end
@@ -0,0 +1,149 @@
1
+ module WithoutScope
2
+ module ActsAsRevisable
3
+ # This module is mixed into the revision classes.
4
+ #
5
+ # ==== Callbacks
6
+ #
7
+ # * +before_restore+ is called on the revision class before it is
8
+ # restored as the current record.
9
+ # * +after_restore+ is called on the revision class after it is
10
+ # restored as the current record.
11
+ module Revision
12
+ def self.included(base) #:nodoc:
13
+ base.send(:extend, ClassMethods)
14
+
15
+ class << base
16
+ attr_accessor :revisable_revisable_class, :revisable_cloned_associations
17
+ end
18
+
19
+ base.instance_eval do
20
+ set_table_name(revisable_class.table_name)
21
+ default_scope :conditions => {:revisable_is_current => false}
22
+
23
+ define_callbacks :before_restore, :after_restore
24
+ before_create :revision_setup
25
+ after_create :grab_my_branches
26
+
27
+ named_scope :deleted, :conditions => ["? is not null", :revisable_deleted_at]
28
+
29
+ [:current_revision, revisable_association_name.to_sym].each do |a|
30
+ belongs_to a, :class_name => revisable_class_name, :foreign_key => :revisable_original_id
31
+ end
32
+
33
+ [[:ancestors, "<"], [:descendants, ">"]].each do |a|
34
+ # Jumping through hoops here to try and make sure the
35
+ # :finder_sql is cross-database compatible. :finder_sql
36
+ # in a plugin is evil but, I see no other option.
37
+ has_many a.first, :class_name => revision_class_name, :finder_sql => "select * from #{quoted_table_name} where #{quote_bound_value(:revisable_original_id)} = \#{revisable_original_id} and #{quote_bound_value(:revisable_number)} #{a.last} \#{revisable_number} and #{quote_bound_value(:revisable_is_current)} = #{quote_value(false)} order by #{quote_bound_value(:revisable_number)} #{(a.last.eql?("<") ? "DESC" : "ASC")}"
38
+ end
39
+ end
40
+ end
41
+
42
+ def find_revision(*args)
43
+ current_revision.find_revision(*args)
44
+ end
45
+
46
+ # Return the revision prior to this one.
47
+ def previous_revision
48
+ self.class.find(:first, :conditions => {:revisable_original_id => revisable_original_id, :revisable_number => revisable_number - 1})
49
+ end
50
+
51
+ # Return the revision after this one.
52
+ def next_revision
53
+ self.class.find(:first, :conditions => {:revisable_original_id => revisable_original_id, :revisable_number => revisable_number + 1})
54
+ end
55
+
56
+ # Setter for revisable_name just to make external API more pleasant.
57
+ def revision_name=(val) #:nodoc:
58
+ self[:revisable_name] = val
59
+ end
60
+
61
+ # Accessor for revisable_name just to make external API more pleasant.
62
+ def revision_name #:nodoc:
63
+ self[:revisable_name]
64
+ end
65
+
66
+ # Sets some initial values for a new revision.
67
+ def revision_setup #:nodoc:
68
+ now = Time.zone.now
69
+ prev = current_revision.revisions.first
70
+ prev.update_attribute(:revisable_revised_at, now) if prev
71
+ self[:revisable_current_at] = now + 1.second
72
+ self[:revisable_is_current] = false
73
+ self[:revisable_branched_from_id] = current_revision[:revisable_branched_from_id]
74
+ self[:revisable_type] = current_revision[:type]
75
+ self[:revisable_number] = (self.class.maximum(:revisable_number, :conditions => {:revisable_original_id => self[:revisable_original_id]}) || 0) + 1
76
+ end
77
+
78
+ def grab_my_branches
79
+ self.class.revisable_class.update_all(["revisable_branched_from_id = ?", self[:id]], ["revisable_branched_from_id = ?", self[:revisable_original_id]])
80
+ end
81
+
82
+ def from_revisable
83
+ current_revision.for_revision
84
+ end
85
+
86
+ def reverting_from
87
+ from_revisable[:reverting_from]
88
+ end
89
+
90
+ def reverting_from=(val)
91
+ from_revisable[:reverting_from] = val
92
+ end
93
+
94
+ def reverting_to
95
+ from_revisable[:reverting_to]
96
+ end
97
+
98
+ def reverting_to=(val)
99
+ from_revisable[:reverting_to] = val
100
+ end
101
+
102
+ module ClassMethods
103
+ # Returns the +revisable_class_name+ as configured in
104
+ # +acts_as_revisable+.
105
+ def revisable_class_name #:nodoc:
106
+ self.revisable_options.revisable_class_name || self.class_name.gsub(/Revision/, '')
107
+ end
108
+
109
+ # Returns the actual +Revisable+ class based on the
110
+ # #revisable_class_name.
111
+ def revisable_class #:nodoc:
112
+ self.revisable_revisable_class ||= self.revisable_class_name.constantize
113
+ end
114
+
115
+ # Returns the revision_class which in this case is simply +self+.
116
+ def revision_class #:nodoc:
117
+ self
118
+ end
119
+
120
+ def revision_class_name #:nodoc:
121
+ self.name
122
+ end
123
+
124
+ # Returns the name of the association acts_as_revision
125
+ # creates.
126
+ def revisable_association_name #:nodoc:
127
+ revisable_class_name.underscore
128
+ end
129
+
130
+ # Returns an array of the associations that should be cloned.
131
+ def revision_cloned_associations #:nodoc:
132
+ clone_associations = self.revisable_options.clone_associations
133
+
134
+ self.revisable_cloned_associations ||= if clone_associations.blank?
135
+ []
136
+ elsif clone_associations.eql? :all
137
+ revisable_class.reflect_on_all_associations.map(&:name)
138
+ elsif clone_associations.is_a? [].class
139
+ clone_associations
140
+ elsif clone_associations[:only]
141
+ [clone_associations[:only]].flatten
142
+ elsif clone_associations[:except]
143
+ revisable_class.reflect_on_all_associations.map(&:name) - [clone_associations[:except]].flatten
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,52 @@
1
+ require 'acts_as_revisable/options'
2
+ require 'acts_as_revisable/quoted_columns'
3
+ require 'acts_as_revisable/acts/common'
4
+ require 'acts_as_revisable/acts/revision'
5
+ require 'acts_as_revisable/acts/revisable'
6
+ require 'acts_as_revisable/acts/deletable'
7
+
8
+ module WithoutScope
9
+ # define the columns used internall by AAR
10
+ REVISABLE_SYSTEM_COLUMNS = %w(revisable_original_id revisable_branched_from_id revisable_number revisable_name revisable_type revisable_current_at revisable_revised_at revisable_deleted_at revisable_is_current)
11
+
12
+ # define the ActiveRecord magic columns that should not be monitored
13
+ REVISABLE_UNREVISABLE_COLUMNS = %w(id type created_at updated_at)
14
+
15
+ module ActsAsRevisable
16
+ def self.included(base)
17
+ base.send(:extend, ClassMethods)
18
+ end
19
+
20
+ module ClassMethods
21
+
22
+ # This +acts_as+ extension provides for making a model the
23
+ # revisable model in an acts_as_revisable pair.
24
+ def acts_as_revisable(*args, &block)
25
+ revisable_shared_setup(args, block)
26
+ self.send(:include, Revisable)
27
+ self.send(:include, Deletable) if self.revisable_options.on_delete == :revise
28
+ end
29
+
30
+ # This +acts_as+ extension provides for making a model the
31
+ # revision model in an acts_as_revisable pair.
32
+ def acts_as_revision(*args, &block)
33
+ revisable_shared_setup(args, block)
34
+ self.send(:include, Revision)
35
+ end
36
+
37
+ private
38
+ # Performs the setup needed for both kinds of acts_as_revisable
39
+ # models.
40
+ def revisable_shared_setup(args, block)
41
+ class << self
42
+ attr_accessor :revisable_options
43
+ end
44
+ options = args.extract_options!
45
+ self.revisable_options = Options.new(options, &block)
46
+
47
+ self.send(:include, Common)
48
+ self.send(:include, WithoutScope::QuotedColumnConditions)
49
+ end
50
+ end
51
+ end
52
+ end