acts_as_versioned-decisiv 3.2.0

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,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 }