acts_as_versioned-decisiv 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ .DS_Store
2
+ test/*.db
3
+ test/debug.log
4
+ Gemfile.lock
@@ -0,0 +1,111 @@
1
+
2
+ [3.2.0]
3
+
4
+ * Copy Work From Here With Better Gem Org - https://github.com/luismreis/acts_as_versioned/
5
+
6
+
7
+ [0.6.2]
8
+
9
+ * (08 Feb 2009) Avoid error with model preload by removing create_versioned_table call in AAV call. [Ngoc Dao]
10
+ * (08 Feb 2009) Do not force updated_at [Ngoc Dao]
11
+ * (08 Feb 2009) Change the create_versioned_table class method to ask the connection if table_exists?. Fixes
12
+ a bug that allows adapters that allow user owned prefixes for table names. [Ken Collins]
13
+
14
+
15
+ [0.6.1]
16
+
17
+ * (29 Dec 2008) Remove #versions_count really. [Ken Collins]
18
+ * (30 Dec 2008) Add assert_sql support in boot.rb. Also changed core lib to order by the has many versions
19
+ association with the version_column, support with tests. [Ken Collins]
20
+
21
+ [0.6]
22
+
23
+ * (23 Dec 2008) Clean up old old code and start move towards new gem [Ken Collins]
24
+ * Starting a .gitignore file.
25
+ * Moving to a test/lib based directory structure with a boot and AAV test case based from ActiveRecord's case.
26
+ * Create rake test and test_dbs tasks.
27
+ * Create a gemspec for publishing as a gem.
28
+
29
+ [0.5.2]
30
+
31
+ * (16 Jun 2008) Backwards Compatibility is overrated (big updates for rails 2.1)
32
+ * Use ActiveRecord 2.1's dirty attribute checking instead [Asa Calow]
33
+ * Remove last traces of #non_versioned_fields
34
+ * Remove AR::Base.find_version and AR::Base.find_versions, rely on AR association proxies and named_scope
35
+ * Remove #versions_count, rely on AR association counter caching.
36
+ * Remove #versioned_attributes, basically the same as AR::Base.versioned_columns
37
+
38
+ * (5 Oct 2006) Allow customization of #versions association options [Dan Peterson]
39
+
40
+ [0.5.1]
41
+
42
+ * (8 Aug 2006) Versioned models now belong to the unversioned model. @article_version.article.class => Article [Aslak Hellesoy]
43
+
44
+ [0.5]
45
+
46
+ * (21 Apr 2006) Added without_locking and without_revision methods.
47
+ Foo.without_revision do
48
+ @foo.update_attributes ...
49
+ end
50
+
51
+ [0.4]
52
+
53
+ * (28 March 2006) Rename non_versioned_fields to non_versioned_columns (old one is kept for compatibility).
54
+ * (28 March 2006) Made explicit documentation note that string column names are required for non_versioned_columns.
55
+
56
+ [0.3.1]
57
+
58
+ * (7 Jan 2006) explicitly set :foreign_key option for the versioned model's belongs_to assocation for STI [Caged]
59
+ * (7 Jan 2006) added tests to prove has_many :through joins work
60
+
61
+ [0.3]
62
+
63
+ * (2 Jan 2006) added ability to share a mixin with versioned class
64
+ * (2 Jan 2006) changed the dynamic version model to MyModel::Version
65
+
66
+ [0.2.4]
67
+
68
+ * (27 Nov 2005) added note about possible destructive behavior of if_changed? [Michael Schuerig]
69
+
70
+ [0.2.3]
71
+
72
+ * (12 Nov 2005) fixed bug with old behavior of #blank? [Michael Schuerig]
73
+ * (12 Nov 2005) updated tests to use ActiveRecord Schema
74
+
75
+ [0.2.2]
76
+
77
+ * (3 Nov 2005) added documentation note to #acts_as_versioned [Martin Jul]
78
+
79
+ [0.2.1]
80
+
81
+ * (6 Oct 2005) renamed dirty? to changed? to keep it uniform. it was aliased to keep it backwards compatible.
82
+
83
+ [0.2]
84
+
85
+ * (6 Oct 2005) added find_versions and find_version class methods.
86
+
87
+ * (6 Oct 2005) removed transaction from create_versioned_table().
88
+ this way you can specify your own transaction around a group of operations.
89
+
90
+ * (30 Sep 2005) fixed bug where find_versions() would order by 'version' twice. (found by Joe Clark)
91
+
92
+ * (26 Sep 2005) added :sequence_name option to acts_as_versioned to set the sequence name on the versioned model
93
+
94
+ [0.1.3]
95
+
96
+ * (18 Sep 2005) First RubyForge release
97
+
98
+ [0.1.2]
99
+
100
+ * check if module is already included when acts_as_versioned is called
101
+
102
+ [0.1.1]
103
+
104
+ * Adding tests and rdocs
105
+
106
+ [0.1]
107
+
108
+ * Initial transfer from Rails ticket: http://dev.rubyonrails.com/ticket/1974
109
+
110
+
111
+
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2005 Rick Olson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,17 @@
1
+
2
+ = ActsAsVersioned Decisiv
3
+
4
+ A fork of Rick Olson's ActsAsVersioned plugin that has been gem'ized along with a few features I need. This library
5
+ adds simple versioning to an ActiveRecord class which of course requires ActiveRecord for use.
6
+
7
+ Has tests for many DBs in ActiveRecord version 2.2.2
8
+
9
+
10
+ == Resources
11
+
12
+ Bundle up.
13
+
14
+ gem 'acts_as_versioned-decisiv', :require => 'acts_as_versioned'
15
+
16
+
17
+
@@ -0,0 +1,13 @@
1
+ require 'bundler'
2
+ require 'rake/testtask'
3
+
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ desc 'Test the AttrStripper plugin.'
7
+ Rake::TestTask.new do |t|
8
+ t.libs = ['lib','test']
9
+ t.test_files = Dir.glob("test/**/*_test.rb").sort
10
+ t.verbose = true
11
+ end
12
+
13
+ task :default => [:test]
@@ -0,0 +1,25 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require "acts_as_versioned/version"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'acts_as_versioned-decisiv'
6
+ s.version = ActiveRecord::Acts::Versioned::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ['Rick Olson','Ken Collins']
9
+ s.email = ['ken@metaskills.net']
10
+ s.homepage = 'http://github.com/Decisiv/acts_as_versioned/'
11
+ s.summary = 'ActiveRecord plugin for versioning your models.'
12
+ s.description = 'ActiveRecord plugin for versioning your models. For Rails 3.'
13
+ s.files = `git ls-files`.split("\n") - ["attr_stripper.gemspec"]
14
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.require_paths = ['lib']
17
+ s.rdoc_options = ['--charset=UTF-8']
18
+ s.add_runtime_dependency 'activerecord', '~> 3.2.0'
19
+ s.add_development_dependency 'sqlite3', '~> 1.3'
20
+ s.add_development_dependency 'rake', '~> 0.9.2'
21
+ s.add_development_dependency 'minitest', '~> 2.8.1'
22
+ s.add_development_dependency 'factory_girl', '~> 2.6.3'
23
+ s.add_development_dependency 'database_cleaner'
24
+ s.add_development_dependency 'forgery'
25
+ end
@@ -0,0 +1,478 @@
1
+ require 'active_record'
2
+ require 'active_support/concern'
3
+
4
+ module ActiveRecord #:nodoc:
5
+ module Acts #:nodoc:
6
+
7
+ # Specify this act if you want to save a copy of the row in a versioned table. This assumes there is a
8
+ # versioned table ready and that your model has a version field. This works with optimistic locking if the lock_version
9
+ # column is present as well.
10
+ #
11
+ # 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
12
+ # your container for the changes to be reflected. In development mode this usually means restarting WEBrick.
13
+ #
14
+ # class Page < ActiveRecord::Base
15
+ # # assumes pages_versions table
16
+ # acts_as_versioned
17
+ # end
18
+ #
19
+ # Example:
20
+ #
21
+ # page = Page.create(:title => 'hello world!')
22
+ # page.version # => 1
23
+ #
24
+ # page.title = 'hello world'
25
+ # page.save
26
+ # page.version # => 2
27
+ # page.versions.size # => 2
28
+ #
29
+ # page.revert_to(1) # using version number
30
+ # page.title # => 'hello world!'
31
+ #
32
+ # page.revert_to(page.versions.last) # using versioned instance
33
+ # page.title # => 'hello world'
34
+ #
35
+ # page.versions.earliest # efficient query to find the first version
36
+ # page.versions.latest # efficient query to find the most recently created version
37
+ #
38
+ #
39
+ # Simple Queries to page between versions
40
+ #
41
+ # page.versions.before(version)
42
+ # page.versions.after(version)
43
+ #
44
+ # Access the previous/next versions from the versioned model itself
45
+ #
46
+ # version = page.versions.latest
47
+ # version.previous # go back one version
48
+ # version.next # go forward one version
49
+ #
50
+ # See ActiveRecord::Acts::Versioned::ClassMethods#acts_as_versioned for configuration options
51
+ module Versioned
52
+
53
+ CALLBACKS = [:set_new_version, :save_version, :save_version?]
54
+
55
+ # == Configuration options
56
+ #
57
+ # * <tt>class_name</tt> - versioned model class name (default: PageVersion in the above example)
58
+ # * <tt>table_name</tt> - versioned model table name (default: page_versions in the above example)
59
+ # * <tt>foreign_key</tt> - foreign key used to relate the versioned model to the original model (default: page_id in the above example)
60
+ # * <tt>inheritance_column</tt> - name of the column to save the model's inheritance_column value for STI. (default: versioned_type)
61
+ # * <tt>version_column</tt> - name of the column in the model that keeps the version number (default: version)
62
+ # * <tt>sequence_name</tt> - name of the custom sequence to be used by the versioned model.
63
+ # * <tt>limit</tt> - number of revisions to keep, defaults to unlimited
64
+ # * <tt>if</tt> - symbol of method to check before saving a new version. If this method returns false, a new version is not saved.
65
+ # For finer control, pass either a Proc or modify Model#version_condition_met?
66
+ #
67
+ # acts_as_versioned :if => Proc.new { |auction| !auction.expired? }
68
+ #
69
+ # or...
70
+ #
71
+ # class Auction
72
+ # def version_condition_met? # totally bypasses the <tt>:if</tt> option
73
+ # !expired?
74
+ # end
75
+ # end
76
+ #
77
+ # * <tt>if_changed</tt> - Simple way of specifying attributes that are required to be changed before saving a model. This takes
78
+ # either a symbol or array of symbols.
79
+ #
80
+ # * <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
81
+ # to create an anonymous mixin:
82
+ #
83
+ # class Auction
84
+ # acts_as_versioned do
85
+ # def started?
86
+ # !started_at.nil?
87
+ # end
88
+ # end
89
+ # end
90
+ #
91
+ # or...
92
+ #
93
+ # module AuctionExtension
94
+ # def started?
95
+ # !started_at.nil?
96
+ # end
97
+ # end
98
+ # class Auction
99
+ # acts_as_versioned :extend => AuctionExtension
100
+ # end
101
+ #
102
+ # Example code:
103
+ #
104
+ # @auction = Auction.find(1)
105
+ # @auction.started?
106
+ # @auction.versions.first.started?
107
+ #
108
+ # == Database Schema
109
+ #
110
+ # The model that you're versioning needs to have a 'version' attribute. The model is versioned
111
+ # into a table called #{model}_versions where the model name is singlular. The _versions table should
112
+ # contain all the fields you want versioned, the same version column, and a #{model}_id foreign key field.
113
+ #
114
+ # A lock_version field is also accepted if your model uses Optimistic Locking. If your table uses Single Table inheritance,
115
+ # then that field is reflected in the versioned model as 'versioned_type' by default.
116
+ #
117
+ # Acts_as_versioned comes prepared with the ActiveRecord::Acts::Versioned::ActMethods::ClassMethods#create_versioned_table
118
+ # method, perfect for a migration. It will also create the version column if the main model does not already have it.
119
+ #
120
+ # class AddVersions < ActiveRecord::Migration
121
+ # def self.up
122
+ # # create_versioned_table takes the same options hash
123
+ # # that create_table does
124
+ # Post.create_versioned_table
125
+ # end
126
+ #
127
+ # def self.down
128
+ # Post.drop_versioned_table
129
+ # end
130
+ # end
131
+ #
132
+ # == Changing What Fields Are Versioned
133
+ #
134
+ # By default, acts_as_versioned will version all but these fields:
135
+ #
136
+ # [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column]
137
+ #
138
+ # You can add or change those by modifying #non_versioned_columns. Note that this takes strings and not symbols.
139
+ #
140
+ # class Post < ActiveRecord::Base
141
+ # acts_as_versioned
142
+ # self.non_versioned_columns << 'comments_count'
143
+ # end
144
+ #
145
+ def acts_as_versioned(options = {}, &extension)
146
+ # don't allow multiple calls
147
+ return if self.included_modules.include?(ActiveRecord::Acts::Versioned::Behaviors)
148
+
149
+ cattr_accessor :versioned_class_name, :versioned_foreign_key, :versioned_table_name, :versioned_inheritance_column,
150
+ :version_column, :max_version_limit, :track_altered_attributes, :version_condition, :version_sequence_name, :non_versioned_columns,
151
+ :version_association_options, :version_if_changed
152
+
153
+ self.versioned_class_name = options[:class_name] || "Version"
154
+ self.versioned_foreign_key = options[:foreign_key] || self.to_s.foreign_key
155
+ self.versioned_table_name = options[:table_name] || "#{table_name_prefix}#{base_class.name.demodulize.underscore}_versions#{table_name_suffix}"
156
+ self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}"
157
+ self.version_column = options[:version_column] || 'version'
158
+ self.version_sequence_name = options[:sequence_name]
159
+ self.max_version_limit = options[:limit].to_i
160
+ self.version_condition = options[:if] || true
161
+ 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)
162
+ self.version_association_options = {
163
+ :class_name => "#{self.to_s}::#{versioned_class_name}",
164
+ :foreign_key => versioned_foreign_key,
165
+ :dependent => :delete_all
166
+ }.merge(options[:association_options] || {})
167
+
168
+ if block_given?
169
+ extension_module_name = "#{versioned_class_name}Extension"
170
+ silence_warnings do
171
+ self.const_set(extension_module_name, Module.new(&extension))
172
+ end
173
+
174
+ options[:extend] = self.const_get(extension_module_name)
175
+ end
176
+
177
+ unless options[:if_changed].nil?
178
+ self.track_altered_attributes = true
179
+ options[:if_changed] = [options[:if_changed]] unless options[:if_changed].is_a?(Array)
180
+ self.version_if_changed = options[:if_changed].map(&:to_s)
181
+ end
182
+
183
+ include options[:extend] if options[:extend].is_a?(Module)
184
+
185
+ include ActiveRecord::Acts::Versioned::Behaviors
186
+
187
+ #
188
+ # Create the dynamic versioned model
189
+ #
190
+ const_set(versioned_class_name, Class.new(ActiveRecord::Base)).class_eval do
191
+ def self.reloadable?;
192
+ false;
193
+ end
194
+
195
+ # find first version before the given version
196
+ def self.before(version)
197
+ where(["#{original_class.versioned_foreign_key} = ? and version < ?", version.send(original_class.versioned_foreign_key), version.version]).
198
+ order('version DESC').
199
+ first
200
+ end
201
+
202
+ # find first version after the given version.
203
+ def self.after(version)
204
+ where(["#{original_class.versioned_foreign_key} = ? and version > ?", version.send(original_class.versioned_foreign_key), version.version]).
205
+ order('version ASC').
206
+ first
207
+ end
208
+
209
+ # finds earliest version of this record
210
+ def self.earliest
211
+ order("#{original_class.version_column}").first
212
+ end
213
+
214
+ # find latest version of this record
215
+ def self.latest
216
+ order("#{original_class.version_column} desc").first
217
+ end
218
+
219
+ def previous
220
+ self.class.before(self)
221
+ end
222
+
223
+ def next
224
+ self.class.after(self)
225
+ end
226
+
227
+ def versions_count
228
+ page.version
229
+ end
230
+ end
231
+
232
+ versioned_class.cattr_accessor :original_class
233
+ versioned_class.original_class = self
234
+ versioned_class.table_name = versioned_table_name
235
+ versioned_class.belongs_to self.to_s.demodulize.underscore.to_sym,
236
+ :class_name => "::#{self.to_s}",
237
+ :foreign_key => versioned_foreign_key
238
+ versioned_class.send :include, options[:extend] if options[:extend].is_a?(Module)
239
+ versioned_class.sequence_name = version_sequence_name if version_sequence_name
240
+ end
241
+
242
+ module Behaviors
243
+ extend ActiveSupport::Concern
244
+
245
+ included do
246
+ has_many :versions, version_association_options
247
+
248
+ before_save :set_new_version
249
+ after_save :save_version
250
+ after_save :clear_old_versions
251
+ end
252
+
253
+ # Saves a version of the model in the versioned table. This is called in the after_save callback by default
254
+ def save_version
255
+ if @saving_version
256
+ @saving_version = nil
257
+ rev = self.class.versioned_class.new
258
+ clone_versioned_model(self, rev)
259
+ rev.send("#{self.class.version_column}=", send(self.class.version_column))
260
+ rev.send("#{self.class.versioned_foreign_key}=", id)
261
+ rev.save
262
+ end
263
+ end
264
+
265
+ # Clears old revisions if a limit is set with the :limit option in <tt>acts_as_versioned</tt>.
266
+ # Override this method to set your own criteria for clearing old versions.
267
+ def clear_old_versions
268
+ return if self.class.max_version_limit == 0
269
+ excess_baggage = send(self.class.version_column).to_i - self.class.max_version_limit
270
+ if excess_baggage > 0
271
+ self.class.versioned_class.delete_all ["#{self.class.version_column} <= ? and #{self.class.versioned_foreign_key} = ?", excess_baggage, id]
272
+ end
273
+ end
274
+
275
+ # Reverts a model to a given version. Takes either a version number or an instance of the versioned model
276
+ def revert_to(version)
277
+ if version.is_a?(self.class.versioned_class)
278
+ return false unless version.send(self.class.versioned_foreign_key) == id and !version.new_record?
279
+ else
280
+ return false unless version = versions.where(self.class.version_column => version).first
281
+ end
282
+ self.clone_versioned_model(version, self)
283
+ send("#{self.class.version_column}=", version.send(self.class.version_column))
284
+ true
285
+ end
286
+
287
+ # Reverts a model to a given version and saves the model.
288
+ # Takes either a version number or an instance of the versioned model
289
+ def revert_to!(version)
290
+ revert_to(version) ? save_without_revision : false
291
+ end
292
+
293
+ # Temporarily turns off Optimistic Locking while saving. Used when reverting so that a new version is not created.
294
+ def save_without_revision
295
+ save_without_revision!
296
+ true
297
+ rescue
298
+ false
299
+ end
300
+
301
+ def save_without_revision!
302
+ without_locking do
303
+ without_revision do
304
+ save!
305
+ end
306
+ end
307
+ end
308
+
309
+ def altered?
310
+ track_altered_attributes ? (version_if_changed - changed).length < version_if_changed.length : changed?
311
+ end
312
+
313
+ # Clones a model. Used when saving a new version or reverting a model's version.
314
+ def clone_versioned_model(orig_model, new_model)
315
+ self.class.versioned_columns.each do |col|
316
+ new_model[col.name] = orig_model.send(col.name) if orig_model.has_attribute?(col.name)
317
+ end
318
+
319
+ if orig_model.is_a?(self.class.versioned_class)
320
+ if new_model.attributes.has_key?(new_model.class.inheritance_column.to_s)
321
+ new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column]
322
+ end
323
+ elsif new_model.is_a?(self.class.versioned_class)
324
+ if new_model.attributes.has_key?(self.class.versioned_inheritance_column.to_s)
325
+ new_model[self.class.versioned_inheritance_column] = orig_model[orig_model.class.inheritance_column]
326
+ end
327
+ end
328
+ end
329
+
330
+ # Checks whether a new version shall be saved or not. Calls <tt>version_condition_met?</tt> and <tt>changed?</tt>.
331
+ def save_version?
332
+ version_condition_met? && altered?
333
+ end
334
+
335
+ # Checks condition set in the :if option to check whether a revision should be created or not. Override this for
336
+ # custom version condition checking.
337
+ def version_condition_met?
338
+ case
339
+ when version_condition.is_a?(Symbol)
340
+ send(version_condition)
341
+ when version_condition.respond_to?(:call) && (version_condition.arity == 1 || version_condition.arity == -1)
342
+ version_condition.call(self)
343
+ else
344
+ version_condition
345
+ end
346
+ end
347
+
348
+ # Executes the block with the versioning callbacks disabled.
349
+ #
350
+ # @foo.without_revision do
351
+ # @foo.save
352
+ # end
353
+ #
354
+ def without_revision(&block)
355
+ self.class.without_revision(&block)
356
+ end
357
+
358
+ # Turns off optimistic locking for the duration of the block
359
+ #
360
+ # @foo.without_locking do
361
+ # @foo.save
362
+ # end
363
+ #
364
+ def without_locking(&block)
365
+ self.class.without_locking(&block)
366
+ end
367
+
368
+ def empty_callback()
369
+ end
370
+
371
+ #:nodoc:
372
+
373
+ protected
374
+ # sets the new version before saving, unless you're using optimistic locking. In that case, let it take care of the version.
375
+ def set_new_version
376
+ @saving_version = new_record? || save_version?
377
+ self.send("#{self.class.version_column}=", next_version) if new_record? || (!locking_enabled? && save_version?)
378
+ end
379
+
380
+ # Gets the next available version for the current record, or 1 for a new record
381
+ def next_version
382
+ (new_record? ? 0 : versions.calculate(:maximum, version_column).to_i) + 1
383
+ end
384
+
385
+ module ClassMethods
386
+ # Returns an array of columns that are versioned. See non_versioned_columns
387
+ def versioned_columns
388
+ @versioned_columns ||= columns.select { |c| !non_versioned_columns.include?(c.name) }
389
+ end
390
+
391
+ # Returns an instance of the dynamic versioned model
392
+ def versioned_class
393
+ const_get versioned_class_name
394
+ end
395
+
396
+ # Rake migration task to create the versioned table using options passed to acts_as_versioned
397
+ def create_versioned_table(create_table_options = {})
398
+ # create version column in main table if it does not exist
399
+ if !self.content_columns.find { |c| [version_column.to_s, 'lock_version'].include? c.name }
400
+ self.connection.add_column table_name, version_column, :integer
401
+ self.reset_column_information
402
+ end
403
+
404
+ return if connection.table_exists?(versioned_table_name)
405
+
406
+ self.connection.create_table(versioned_table_name, create_table_options) do |t|
407
+ t.column versioned_foreign_key, :integer
408
+ t.column version_column, :integer
409
+ end
410
+
411
+ self.versioned_columns.each do |col|
412
+ self.connection.add_column versioned_table_name, col.name, col.type,
413
+ :limit => col.limit,
414
+ :default => col.default,
415
+ :scale => col.scale,
416
+ :precision => col.precision
417
+ end
418
+
419
+ if type_col = self.columns_hash[inheritance_column]
420
+ self.connection.add_column versioned_table_name, versioned_inheritance_column, type_col.type,
421
+ :limit => type_col.limit,
422
+ :default => type_col.default,
423
+ :scale => type_col.scale,
424
+ :precision => type_col.precision
425
+ end
426
+
427
+ self.connection.add_index versioned_table_name, versioned_foreign_key
428
+ end
429
+
430
+ # Rake migration task to drop the versioned table
431
+ def drop_versioned_table
432
+ self.connection.drop_table versioned_table_name
433
+ end
434
+
435
+ # Executes the block with the versioning callbacks disabled.
436
+ #
437
+ # Foo.without_revision do
438
+ # @foo.save
439
+ # end
440
+ #
441
+ def without_revision(&block)
442
+ class_eval do
443
+ CALLBACKS.each do |attr_name|
444
+ alias_method "orig_#{attr_name}".to_sym, attr_name
445
+ alias_method attr_name, :empty_callback
446
+ end
447
+ end
448
+ block.call
449
+ ensure
450
+ class_eval do
451
+ CALLBACKS.each do |attr_name|
452
+ alias_method attr_name, "orig_#{attr_name}".to_sym
453
+ end
454
+ end
455
+ end
456
+
457
+ # Turns off optimistic locking for the duration of the block
458
+ #
459
+ # Foo.without_locking do
460
+ # @foo.save
461
+ # end
462
+ #
463
+ def without_locking(&block)
464
+ current = ActiveRecord::Base.lock_optimistically
465
+ ActiveRecord::Base.lock_optimistically = false if current
466
+ begin
467
+ block.call
468
+ ensure
469
+ ActiveRecord::Base.lock_optimistically = true if current
470
+ end
471
+ end
472
+ end
473
+ end
474
+ end
475
+ end
476
+ end
477
+
478
+ ActiveSupport.on_load(:active_record) { extend ActiveRecord::Acts::Versioned }