Commit 4001b435cc8e42f14a80853eae274b6472b95a21
1 parent
8042c0ea
Exists in
staging
and in
42 other branches
rails3: update acts_as_versioned to a rails3 compatible version
Showing
28 changed files
with
513 additions
and
1240 deletions
Show diff stats
| ... | ... | @@ -0,0 +1 @@ |
| 1 | +rvm --create use 1.9.2@acts_as_versioned | ... | ... |
vendor/plugins/acts_as_versioned/CHANGELOG
| ... | ... | @@ -1,82 +0,0 @@ |
| 1 | -*GIT* (version numbers are overrated) | |
| 2 | - | |
| 3 | -* (16 Jun 2008) Backwards Compatibility is overrated (big updates for rails 2.1) | |
| 4 | - | |
| 5 | - * Use ActiveRecord 2.1's dirty attribute checking instead [Asa Calow] | |
| 6 | - * Remove last traces of #non_versioned_fields | |
| 7 | - * Remove AR::Base.find_version and AR::Base.find_versions, rely on AR association proxies and named_scope | |
| 8 | - * Remove #versions_count, rely on AR association counter caching. | |
| 9 | - * Remove #versioned_attributes, basically the same as AR::Base.versioned_columns | |
| 10 | - | |
| 11 | -* (5 Oct 2006) Allow customization of #versions association options [Dan Peterson] | |
| 12 | - | |
| 13 | -*0.5.1* | |
| 14 | - | |
| 15 | -* (8 Aug 2006) Versioned models now belong to the unversioned model. @article_version.article.class => Article [Aslak Hellesoy] | |
| 16 | - | |
| 17 | -*0.5* # do versions even matter for plugins? | |
| 18 | - | |
| 19 | -* (21 Apr 2006) Added without_locking and without_revision methods. | |
| 20 | - | |
| 21 | - Foo.without_revision do | |
| 22 | - @foo.update_attributes ... | |
| 23 | - end | |
| 24 | - | |
| 25 | -*0.4* | |
| 26 | - | |
| 27 | -* (28 March 2006) Rename non_versioned_fields to non_versioned_columns (old one is kept for compatibility). | |
| 28 | -* (28 March 2006) Made explicit documentation note that string column names are required for non_versioned_columns. | |
| 29 | - | |
| 30 | -*0.3.1* | |
| 31 | - | |
| 32 | -* (7 Jan 2006) explicitly set :foreign_key option for the versioned model's belongs_to assocation for STI [Caged] | |
| 33 | -* (7 Jan 2006) added tests to prove has_many :through joins work | |
| 34 | - | |
| 35 | -*0.3* | |
| 36 | - | |
| 37 | -* (2 Jan 2006) added ability to share a mixin with versioned class | |
| 38 | -* (2 Jan 2006) changed the dynamic version model to MyModel::Version | |
| 39 | - | |
| 40 | -*0.2.4* | |
| 41 | - | |
| 42 | -* (27 Nov 2005) added note about possible destructive behavior of if_changed? [Michael Schuerig] | |
| 43 | - | |
| 44 | -*0.2.3* | |
| 45 | - | |
| 46 | -* (12 Nov 2005) fixed bug with old behavior of #blank? [Michael Schuerig] | |
| 47 | -* (12 Nov 2005) updated tests to use ActiveRecord Schema | |
| 48 | - | |
| 49 | -*0.2.2* | |
| 50 | - | |
| 51 | -* (3 Nov 2005) added documentation note to #acts_as_versioned [Martin Jul] | |
| 52 | - | |
| 53 | -*0.2.1* | |
| 54 | - | |
| 55 | -* (6 Oct 2005) renamed dirty? to changed? to keep it uniform. it was aliased to keep it backwards compatible. | |
| 56 | - | |
| 57 | -*0.2* | |
| 58 | - | |
| 59 | -* (6 Oct 2005) added find_versions and find_version class methods. | |
| 60 | - | |
| 61 | -* (6 Oct 2005) removed transaction from create_versioned_table(). | |
| 62 | - this way you can specify your own transaction around a group of operations. | |
| 63 | - | |
| 64 | -* (30 Sep 2005) fixed bug where find_versions() would order by 'version' twice. (found by Joe Clark) | |
| 65 | - | |
| 66 | -* (26 Sep 2005) added :sequence_name option to acts_as_versioned to set the sequence name on the versioned model | |
| 67 | - | |
| 68 | -*0.1.3* (18 Sep 2005) | |
| 69 | - | |
| 70 | -* First RubyForge release | |
| 71 | - | |
| 72 | -*0.1.2* | |
| 73 | - | |
| 74 | -* check if module is already included when acts_as_versioned is called | |
| 75 | - | |
| 76 | -*0.1.1* | |
| 77 | - | |
| 78 | -* Adding tests and rdocs | |
| 79 | - | |
| 80 | -*0.1* | |
| 81 | - | |
| 82 | -* Initial transfer from Rails ticket: http://dev.rubyonrails.com/ticket/1974 | |
| 83 | 0 | \ No newline at end of file |
| ... | ... | @@ -0,0 +1,101 @@ |
| 1 | +GEM | |
| 2 | + remote: http://rubygems.org/ | |
| 3 | + specs: | |
| 4 | + actionmailer (3.1.4) | |
| 5 | + actionpack (= 3.1.4) | |
| 6 | + mail (~> 2.3.0) | |
| 7 | + actionpack (3.1.4) | |
| 8 | + activemodel (= 3.1.4) | |
| 9 | + activesupport (= 3.1.4) | |
| 10 | + builder (~> 3.0.0) | |
| 11 | + erubis (~> 2.7.0) | |
| 12 | + i18n (~> 0.6) | |
| 13 | + rack (~> 1.3.6) | |
| 14 | + rack-cache (~> 1.1) | |
| 15 | + rack-mount (~> 0.8.2) | |
| 16 | + rack-test (~> 0.6.1) | |
| 17 | + sprockets (~> 2.0.3) | |
| 18 | + activemodel (3.1.4) | |
| 19 | + activesupport (= 3.1.4) | |
| 20 | + builder (~> 3.0.0) | |
| 21 | + i18n (~> 0.6) | |
| 22 | + activerecord (3.1.4) | |
| 23 | + activemodel (= 3.1.4) | |
| 24 | + activesupport (= 3.1.4) | |
| 25 | + arel (~> 2.2.3) | |
| 26 | + tzinfo (~> 0.3.29) | |
| 27 | + activeresource (3.1.4) | |
| 28 | + activemodel (= 3.1.4) | |
| 29 | + activesupport (= 3.1.4) | |
| 30 | + activesupport (3.1.4) | |
| 31 | + multi_json (~> 1.0) | |
| 32 | + allison (2.0.3) | |
| 33 | + arel (2.2.3) | |
| 34 | + builder (3.0.0) | |
| 35 | + echoe (4.6.3) | |
| 36 | + allison (>= 2.0.3) | |
| 37 | + gemcutter (>= 0.7.0) | |
| 38 | + rake (>= 0.9.2) | |
| 39 | + rdoc (>= 3.6.1) | |
| 40 | + rubyforge (>= 2.0.4) | |
| 41 | + erubis (2.7.0) | |
| 42 | + gemcutter (0.7.1) | |
| 43 | + hike (1.2.1) | |
| 44 | + i18n (0.6.0) | |
| 45 | + json (1.6.6) | |
| 46 | + json_pure (1.7.7) | |
| 47 | + mail (2.3.3) | |
| 48 | + i18n (>= 0.4.0) | |
| 49 | + mime-types (~> 1.16) | |
| 50 | + treetop (~> 1.4.8) | |
| 51 | + mime-types (1.18) | |
| 52 | + multi_json (1.2.0) | |
| 53 | + polyglot (0.3.3) | |
| 54 | + rack (1.3.6) | |
| 55 | + rack-cache (1.2) | |
| 56 | + rack (>= 0.4) | |
| 57 | + rack-mount (0.8.3) | |
| 58 | + rack (>= 1.0.0) | |
| 59 | + rack-ssl (1.3.2) | |
| 60 | + rack | |
| 61 | + rack-test (0.6.1) | |
| 62 | + rack (>= 1.0) | |
| 63 | + rails (3.1.4) | |
| 64 | + actionmailer (= 3.1.4) | |
| 65 | + actionpack (= 3.1.4) | |
| 66 | + activerecord (= 3.1.4) | |
| 67 | + activeresource (= 3.1.4) | |
| 68 | + activesupport (= 3.1.4) | |
| 69 | + bundler (~> 1.0) | |
| 70 | + railties (= 3.1.4) | |
| 71 | + railties (3.1.4) | |
| 72 | + actionpack (= 3.1.4) | |
| 73 | + activesupport (= 3.1.4) | |
| 74 | + rack-ssl (~> 1.3.2) | |
| 75 | + rake (>= 0.8.7) | |
| 76 | + rdoc (~> 3.4) | |
| 77 | + thor (~> 0.14.6) | |
| 78 | + rake (0.9.2.2) | |
| 79 | + rdoc (3.12) | |
| 80 | + json (~> 1.4) | |
| 81 | + rubyforge (2.0.4) | |
| 82 | + json_pure (>= 1.1.7) | |
| 83 | + sprockets (2.0.3) | |
| 84 | + hike (~> 1.2) | |
| 85 | + rack (~> 1.0) | |
| 86 | + tilt (~> 1.1, != 1.3.0) | |
| 87 | + sqlite3 (1.3.5) | |
| 88 | + thor (0.14.6) | |
| 89 | + tilt (1.3.3) | |
| 90 | + treetop (1.4.10) | |
| 91 | + polyglot | |
| 92 | + polyglot (>= 0.3.1) | |
| 93 | + tzinfo (0.3.33) | |
| 94 | + | |
| 95 | +PLATFORMS | |
| 96 | + ruby | |
| 97 | + | |
| 98 | +DEPENDENCIES | |
| 99 | + echoe | |
| 100 | + rails (~> 3.1.0) | |
| 101 | + sqlite3 | ... | ... |
vendor/plugins/acts_as_versioned/README
| ... | ... | @@ -1,28 +0,0 @@ |
| 1 | -= acts_as_versioned | |
| 2 | - | |
| 3 | -This library adds simple versioning to an ActiveRecord module. ActiveRecord is required. | |
| 4 | - | |
| 5 | -== Resources | |
| 6 | - | |
| 7 | -Install | |
| 8 | - | |
| 9 | -* gem install acts_as_versioned | |
| 10 | - | |
| 11 | -Rubyforge project | |
| 12 | - | |
| 13 | -* http://rubyforge.org/projects/ar-versioned | |
| 14 | - | |
| 15 | -RDocs | |
| 16 | - | |
| 17 | -* http://ar-versioned.rubyforge.org | |
| 18 | - | |
| 19 | -Subversion | |
| 20 | - | |
| 21 | -* http://techno-weenie.net/svn/projects/acts_as_versioned | |
| 22 | - | |
| 23 | -Collaboa | |
| 24 | - | |
| 25 | -* http://collaboa.techno-weenie.net/repository/browse/acts_as_versioned | |
| 26 | - | |
| 27 | -Special thanks to Dreamer on ##rubyonrails for help in early testing. His ServerSideWiki (http://serversidewiki.com) | |
| 28 | -was the first project to use acts_as_versioned <em>in the wild</em>. | |
| 29 | 0 | \ No newline at end of file |
| ... | ... | @@ -0,0 +1,120 @@ |
| 1 | +## About ## | |
| 2 | +===== | |
| 3 | + | |
| 4 | +acts_as_versioned is a gem for Rails 3.1 & 3.2 to enable easy versioning of models. As a versioned model is updated revisions are kept in a seperate table, providing a record of what changed. | |
| 5 | + | |
| 6 | +## Getting Started ## | |
| 7 | +===== | |
| 8 | + | |
| 9 | +In your Gemfile simply include: | |
| 10 | + | |
| 11 | + gem 'acts_as_versioned', :git => 'https://github.com/jwhitehorn/acts_as_versioned.git' | |
| 12 | + | |
| 13 | +The next time you run `bundle install` you'll be all set to start using acts_as_versioned. | |
| 14 | + | |
| 15 | +## Usage ## | |
| 16 | +===== | |
| 17 | + | |
| 18 | +#### Versioning a Model #### | |
| 19 | +By default acts_as_versioned is unobtrusive. You will need to explicitly state which models to version. To do so, add the line `acts_as_versioned` to your model, like so: | |
| 20 | + | |
| 21 | + class MyModel < ActiveRecord::Base | |
| 22 | + acts_as_versioned | |
| 23 | + #... | |
| 24 | + end | |
| 25 | + | |
| 26 | +Next we need to create a migration to setup our versioning tables: | |
| 27 | + | |
| 28 | + bundle exec rails generate migration AddVersioningToMyModel | |
| 29 | + | |
| 30 | +Once that is completed, edit the generated migration. acts_as_versioned patches your model to add a `create_versioned_table` and `drop_versioned_table` method. A migration for `MyModel` (assuming MyModel already existed) might look like: | |
| 31 | + | |
| 32 | + class AddVersioningToMyModel < ActiveRecord::Migration | |
| 33 | + def self.up | |
| 34 | + MyModel.create_versioned_table | |
| 35 | + end | |
| 36 | + | |
| 37 | + def self.down | |
| 38 | + MyModel.drop_versioned_table | |
| 39 | + end | |
| 40 | + end | |
| 41 | + | |
| 42 | +Execute your migration: | |
| 43 | + | |
| 44 | + bundle exec rake db:migrate | |
| 45 | + | |
| 46 | +And you're finished! Without any addition work, `MyModel` is being versioned. | |
| 47 | + | |
| 48 | +#### Excluding attributes from versioning #### | |
| 49 | + | |
| 50 | +Sometime you want to exclude an attribute of a model from being versioned. That can be accomplished with the `:except` paramter to `acts_as_versioned`: | |
| 51 | + | |
| 52 | + class MyMode < ActiveRecord::Base | |
| 53 | + acts_as_versioned :except => :some_attr_i_dont_want_versioned | |
| 54 | + | |
| 55 | + end | |
| 56 | + | |
| 57 | + | |
| 58 | +#### Revisions #### | |
| 59 | + | |
| 60 | +Recording a history of changes to a model is only useful if you can do something with that data. With acts_as_versioned there are several ways you can interact with a model's revisions. | |
| 61 | + | |
| 62 | +##### Version Number ##### | |
| 63 | +To determine what the current version number for a model is: | |
| 64 | + | |
| 65 | + model.version | |
| 66 | + | |
| 67 | +The `version` attribute is available for both the actual model, and also any revisions of a model. Thusly, the following is valid: | |
| 68 | + | |
| 69 | + model.versions.last.version | |
| 70 | + | |
| 71 | +##### Revisions List ##### | |
| 72 | +As alluded to above, you can get an array of revisions of a model via the `versions` attribute: | |
| 73 | + | |
| 74 | + model.versions | |
| 75 | + | |
| 76 | +The returned objects are of a type `MyModel::Version` where `MyModel` is the model you are working with. These objects have identical fields to `MyModel`. So, if `MyModel` had a `name` attribute, you could also say: | |
| 77 | + | |
| 78 | + model.versions.last.name | |
| 79 | + | |
| 80 | +##### Reverting to a Revision ##### | |
| 81 | +To revert a model to an older revision, simply call `revert_to` with the version number you desire to rever to: | |
| 82 | + | |
| 83 | + model.revert_to(version_number) | |
| 84 | + | |
| 85 | +##### Saving Without Revisions ##### | |
| 86 | +Occasionally you might need to save a model without necessary creating revisions. To do so, use the `save_without_revision` method: | |
| 87 | + | |
| 88 | + model.save_without_revision | |
| 89 | + | |
| 90 | + | |
| 91 | +#### Migrations #### | |
| 92 | +Adding a field to your model does not automatically add it to the versioning table. So, when you add new fields, be sure to add them to both: | |
| 93 | + | |
| 94 | + class AddNewFieldToMyModel < ActiveRecord::Migration | |
| 95 | + def change | |
| 96 | + add_column :my_models, :new_field_, :string | |
| 97 | + add_column :my_model_versions, :new_field_, :string | |
| 98 | + end | |
| 99 | + end | |
| 100 | + | |
| 101 | +#### Version Class #### | |
| 102 | +As has been stated, the versioned data is stored seperately from the main class. This also implies that `model.versions` returns an area of object of a class _other_ than `MyModel` (where `model` is an instance of `MyModel`, keeping with our working example). The instances returned are actually of type `MyModel::Version`. With this, comes the fact that any methods, associations, etc. defined on `MyModel` are not present on `MyModel::Version`. | |
| 103 | + | |
| 104 | +While this sounds obvious, it can some times be unexpected. Especially when acts_as_versioned make it so easy to grab historical records from a live record. A common scenario where this can come up is associations. | |
| 105 | + | |
| 106 | +Say `MyModel` belongs to `TheMan`. Also, assume that you want to find out where (in the past) a particular instance of `MyModel` was updated in regards to it's association to `TheMan`. You could write that as: | |
| 107 | + | |
| 108 | + model.versions.keep_if { |m| m.the_man != current_man }.last | |
| 109 | + | |
| 110 | +However, this will not work. This is because `MyModel::Version` does _not_ belong to `TheMan`. You could compare ids here, or you could patch `MyModel::Version` to belong to `TheMan` like: | |
| 111 | + | |
| 112 | + class MyModel | |
| 113 | + acts_as_versioned | |
| 114 | + belongs_to :the_men | |
| 115 | + #some stuff | |
| 116 | + | |
| 117 | + class Version | |
| 118 | + belongs_to :the_men | |
| 119 | + end | |
| 120 | + end | |
| 0 | 121 | \ No newline at end of file | ... | ... |
vendor/plugins/acts_as_versioned/Rakefile
| 1 | -require 'rubygems' | |
| 2 | - | |
| 3 | -require 'rake/rdoctask' | |
| 4 | -require 'rake/packagetask' | |
| 5 | -require 'rake/gempackagetask' | |
| 6 | -require 'rake/testtask' | |
| 7 | -require 'rake/contrib/rubyforgepublisher' | |
| 8 | - | |
| 9 | -PKG_NAME = 'acts_as_versioned' | |
| 10 | -PKG_VERSION = '0.3.1' | |
| 11 | -PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}" | |
| 12 | -PROD_HOST = "technoweenie@bidwell.textdrive.com" | |
| 13 | -RUBY_FORGE_PROJECT = 'ar-versioned' | |
| 14 | -RUBY_FORGE_USER = 'technoweenie' | |
| 15 | - | |
| 16 | -desc 'Default: run unit tests.' | |
| 17 | -task :default => :test | |
| 18 | - | |
| 19 | -desc 'Test the calculations plugin.' | |
| 20 | -Rake::TestTask.new(:test) do |t| | |
| 21 | - t.libs << 'lib' | |
| 22 | - t.pattern = 'test/**/*_test.rb' | |
| 23 | - t.verbose = true | |
| 24 | -end | |
| 25 | - | |
| 26 | -desc 'Generate documentation for the calculations plugin.' | |
| 27 | -Rake::RDocTask.new(:rdoc) do |rdoc| | |
| 28 | - rdoc.rdoc_dir = 'rdoc' | |
| 29 | - rdoc.title = "#{PKG_NAME} -- Simple versioning with active record models" | |
| 30 | - rdoc.options << '--line-numbers --inline-source' | |
| 31 | - rdoc.rdoc_files.include('README', 'CHANGELOG', 'RUNNING_UNIT_TESTS') | |
| 32 | - rdoc.rdoc_files.include('lib/**/*.rb') | |
| 33 | -end | |
| 34 | - | |
| 35 | -spec = Gem::Specification.new do |s| | |
| 36 | - s.name = PKG_NAME | |
| 37 | - s.version = PKG_VERSION | |
| 38 | - s.platform = Gem::Platform::RUBY | |
| 39 | - s.summary = "Simple versioning with active record models" | |
| 40 | - s.files = FileList["{lib,test}/**/*"].to_a + %w(README MIT-LICENSE CHANGELOG RUNNING_UNIT_TESTS) | |
| 41 | - s.files.delete "acts_as_versioned_plugin.sqlite.db" | |
| 42 | - s.files.delete "acts_as_versioned_plugin.sqlite3.db" | |
| 43 | - s.files.delete "test/debug.log" | |
| 44 | - s.require_path = 'lib' | |
| 45 | - s.autorequire = 'acts_as_versioned' | |
| 46 | - s.has_rdoc = true | |
| 47 | - s.test_files = Dir['test/**/*_test.rb'] | |
| 48 | - s.add_dependency 'activerecord', '>= 1.10.1' | |
| 49 | - s.add_dependency 'activesupport', '>= 1.1.1' | |
| 50 | - s.author = "Rick Olson" | |
| 51 | - s.email = "technoweenie@gmail.com" | |
| 52 | - s.homepage = "http://techno-weenie.net" | |
| 53 | -end | |
| 54 | - | |
| 55 | -Rake::GemPackageTask.new(spec) do |pkg| | |
| 56 | - pkg.need_tar = true | |
| 57 | -end | |
| 58 | - | |
| 59 | -desc "Publish the API documentation" | |
| 60 | -task :pdoc => [:rdoc] do | |
| 61 | - Rake::RubyForgePublisher.new(RUBY_FORGE_PROJECT, RUBY_FORGE_USER).upload | |
| 62 | -end | |
| 63 | - | |
| 64 | -desc 'Publish the gem and API docs' | |
| 65 | -task :publish => [:pdoc, :rubyforge_upload] | |
| 66 | - | |
| 67 | -desc "Publish the release files to RubyForge." | |
| 68 | -task :rubyforge_upload => :package do | |
| 69 | - files = %w(gem tgz).map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" } | |
| 70 | - | |
| 71 | - if RUBY_FORGE_PROJECT then | |
| 72 | - require 'net/http' | |
| 73 | - require 'open-uri' | |
| 74 | - | |
| 75 | - project_uri = "http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/" | |
| 76 | - project_data = open(project_uri) { |data| data.read } | |
| 77 | - group_id = project_data[/[?&]group_id=(\d+)/, 1] | |
| 78 | - raise "Couldn't get group id" unless group_id | |
| 79 | - | |
| 80 | - # This echos password to shell which is a bit sucky | |
| 81 | - if ENV["RUBY_FORGE_PASSWORD"] | |
| 82 | - password = ENV["RUBY_FORGE_PASSWORD"] | |
| 83 | - else | |
| 84 | - print "#{RUBY_FORGE_USER}@rubyforge.org's password: " | |
| 85 | - password = STDIN.gets.chomp | |
| 86 | - end | |
| 87 | - | |
| 88 | - login_response = Net::HTTP.start("rubyforge.org", 80) do |http| | |
| 89 | - data = [ | |
| 90 | - "login=1", | |
| 91 | - "form_loginname=#{RUBY_FORGE_USER}", | |
| 92 | - "form_pw=#{password}" | |
| 93 | - ].join("&") | |
| 94 | - http.post("/account/login.php", data) | |
| 95 | - end | |
| 96 | - | |
| 97 | - cookie = login_response["set-cookie"] | |
| 98 | - raise "Login failed" unless cookie | |
| 99 | - headers = { "Cookie" => cookie } | |
| 100 | - | |
| 101 | - release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}" | |
| 102 | - release_data = open(release_uri, headers) { |data| data.read } | |
| 103 | - package_id = release_data[/[?&]package_id=(\d+)/, 1] | |
| 104 | - raise "Couldn't get package id" unless package_id | |
| 105 | - | |
| 106 | - first_file = true | |
| 107 | - release_id = "" | |
| 108 | - | |
| 109 | - files.each do |filename| | |
| 110 | - basename = File.basename(filename) | |
| 111 | - file_ext = File.extname(filename) | |
| 112 | - file_data = File.open(filename, "rb") { |file| file.read } | |
| 113 | - | |
| 114 | - puts "Releasing #{basename}..." | |
| 115 | - | |
| 116 | - release_response = Net::HTTP.start("rubyforge.org", 80) do |http| | |
| 117 | - release_date = Time.now.strftime("%Y-%m-%d %H:%M") | |
| 118 | - type_map = { | |
| 119 | - ".zip" => "3000", | |
| 120 | - ".tgz" => "3110", | |
| 121 | - ".gz" => "3110", | |
| 122 | - ".gem" => "1400" | |
| 123 | - }; type_map.default = "9999" | |
| 124 | - type = type_map[file_ext] | |
| 125 | - boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor" | |
| 126 | - | |
| 127 | - query_hash = if first_file then | |
| 128 | - { | |
| 129 | - "group_id" => group_id, | |
| 130 | - "package_id" => package_id, | |
| 131 | - "release_name" => PKG_FILE_NAME, | |
| 132 | - "release_date" => release_date, | |
| 133 | - "type_id" => type, | |
| 134 | - "processor_id" => "8000", # Any | |
| 135 | - "release_notes" => "", | |
| 136 | - "release_changes" => "", | |
| 137 | - "preformatted" => "1", | |
| 138 | - "submit" => "1" | |
| 139 | - } | |
| 140 | - else | |
| 141 | - { | |
| 142 | - "group_id" => group_id, | |
| 143 | - "release_id" => release_id, | |
| 144 | - "package_id" => package_id, | |
| 145 | - "step2" => "1", | |
| 146 | - "type_id" => type, | |
| 147 | - "processor_id" => "8000", # Any | |
| 148 | - "submit" => "Add This File" | |
| 149 | - } | |
| 150 | - end | |
| 151 | - | |
| 152 | - query = "?" + query_hash.map do |(name, value)| | |
| 153 | - [name, URI.encode(value)].join("=") | |
| 154 | - end.join("&") | |
| 155 | - | |
| 156 | - data = [ | |
| 157 | - "--" + boundary, | |
| 158 | - "Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"", | |
| 159 | - "Content-Type: application/octet-stream", | |
| 160 | - "Content-Transfer-Encoding: binary", | |
| 161 | - "", file_data, "" | |
| 162 | - ].join("\x0D\x0A") | |
| 163 | - | |
| 164 | - release_headers = headers.merge( | |
| 165 | - "Content-Type" => "multipart/form-data; boundary=#{boundary}" | |
| 166 | - ) | |
| 167 | - | |
| 168 | - target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php" | |
| 169 | - http.post(target + query, data, release_headers) | |
| 170 | - end | |
| 171 | - | |
| 172 | - if first_file then | |
| 173 | - release_id = release_response.body[/release_id=(\d+)/, 1] | |
| 174 | - raise("Couldn't get release id") unless release_id | |
| 175 | - end | |
| 176 | - | |
| 177 | - first_file = false | |
| 178 | - end | |
| 179 | - end | |
| 180 | -end | |
| 181 | 1 | \ No newline at end of file |
| 2 | +require 'rubygems' | |
| 3 | +require 'rake' | |
| 4 | +require 'echoe' | |
| 5 | + | |
| 6 | +Echoe.new('acts_as_versioned', '3.2.1') do |p| | |
| 7 | + p.description = "Active Record model versioning" | |
| 8 | + p.url = "http://github.com/jwhitehorn/acts_as_versioned" | |
| 9 | + p.author = "Jason Whitehorn" | |
| 10 | + p.email = "jason.whitehorn@gmail.com" | |
| 11 | + p.dependencies = ['activerecord'] | |
| 12 | +end | |
| 13 | + | |
| 14 | +Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext } | |
| 182 | 15 | \ No newline at end of file | ... | ... |
vendor/plugins/acts_as_versioned/VERSION.yml
vendor/plugins/acts_as_versioned/acts_as_versioned.gemspec
| 1 | 1 | # -*- encoding: utf-8 -*- |
| 2 | 2 | |
| 3 | 3 | Gem::Specification.new do |s| |
| 4 | - s.name = %q{acts_as_versioned} | |
| 5 | - s.version = "0.5.2" | |
| 4 | + s.name = "acts_as_versioned" | |
| 5 | + s.version = "3.2.1" | |
| 6 | 6 | |
| 7 | - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= | |
| 8 | - s.authors = ["technoweenie"] | |
| 9 | - s.date = %q{2009-01-20} | |
| 10 | - s.description = %q{TODO} | |
| 11 | - s.email = %q{technoweenie@bidwell.textdrive.com} | |
| 12 | - s.files = ["VERSION.yml", "lib/acts_as_versioned.rb", "test/abstract_unit.rb", "test/database.yml", "test/fixtures", "test/fixtures/authors.yml", "test/fixtures/landmark.rb", "test/fixtures/landmark_versions.yml", "test/fixtures/landmarks.yml", "test/fixtures/locked_pages.yml", "test/fixtures/locked_pages_revisions.yml", "test/fixtures/migrations", "test/fixtures/migrations/1_add_versioned_tables.rb", "test/fixtures/page.rb", "test/fixtures/page_versions.yml", "test/fixtures/pages.yml", "test/fixtures/widget.rb", "test/migration_test.rb", "test/schema.rb", "test/versioned_test.rb"] | |
| 13 | - s.has_rdoc = true | |
| 14 | - s.homepage = %q{http://github.com/technoweenie/acts_as_versioned} | |
| 15 | - s.rdoc_options = ["--inline-source", "--charset=UTF-8"] | |
| 7 | + s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version= | |
| 8 | + s.authors = ["Jason Whitehorn"] | |
| 9 | + s.date = "2013-05-03" | |
| 10 | + s.description = "Active Record model versioning" | |
| 11 | + s.email = "jason.whitehorn@gmail.com" | |
| 12 | + s.extra_rdoc_files = ["README.md", "lib/acts_as_versioned.rb"] | |
| 13 | + s.files = ["Gemfile", "Gemfile.lock", "MIT-LICENSE", "Manifest", "README.md", "RUNNING_UNIT_TESTS", "Rakefile", "acts_as_versioned.gemspec", "acts_as_versioned_plugin.sqlite3.db", "init.rb", "lib/acts_as_versioned.rb"] | |
| 14 | + s.homepage = "http://github.com/jwhitehorn/acts_as_versioned" | |
| 15 | + s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Acts_as_versioned", "--main", "README.md"] | |
| 16 | 16 | s.require_paths = ["lib"] |
| 17 | - s.rubygems_version = %q{1.3.1} | |
| 18 | - s.summary = %q{TODO} | |
| 17 | + s.rubyforge_project = "acts_as_versioned" | |
| 18 | + s.rubygems_version = "1.8.25" | |
| 19 | + s.summary = "Active Record model versioning" | |
| 19 | 20 | |
| 20 | 21 | if s.respond_to? :specification_version then |
| 21 | - current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION | |
| 22 | - s.specification_version = 2 | |
| 22 | + s.specification_version = 3 | |
| 23 | 23 | |
| 24 | - if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then | |
| 24 | + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then | |
| 25 | + s.add_runtime_dependency(%q<activerecord>, [">= 0"]) | |
| 25 | 26 | else |
| 27 | + s.add_dependency(%q<activerecord>, [">= 0"]) | |
| 26 | 28 | end |
| 27 | 29 | else |
| 30 | + s.add_dependency(%q<activerecord>, [">= 0"]) | |
| 28 | 31 | end |
| 29 | 32 | end | ... | ... |
vendor/plugins/acts_as_versioned/lib/acts_as_versioned.rb
| ... | ... | @@ -18,6 +18,7 @@ |
| 18 | 18 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| 19 | 19 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 20 | 20 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 21 | +require 'active_support/concern' | |
| 21 | 22 | |
| 22 | 23 | module ActiveRecord #:nodoc: |
| 23 | 24 | module Acts #:nodoc: |
| ... | ... | @@ -66,203 +67,206 @@ module ActiveRecord #:nodoc: |
| 66 | 67 | # |
| 67 | 68 | # See ActiveRecord::Acts::Versioned::ClassMethods#acts_as_versioned for configuration options |
| 68 | 69 | module Versioned |
| 70 | + VERSION = "0.6.0" | |
| 69 | 71 | CALLBACKS = [:set_new_version, :save_version, :save_version?] |
| 70 | - def self.included(base) # :nodoc: | |
| 71 | - base.extend ClassMethods | |
| 72 | - end | |
| 73 | 72 | |
| 74 | - module ClassMethods | |
| 75 | - # == Configuration options | |
| 76 | - # | |
| 77 | - # * <tt>class_name</tt> - versioned model class name (default: PageVersion in the above example) | |
| 78 | - # * <tt>table_name</tt> - versioned model table name (default: page_versions in the above example) | |
| 79 | - # * <tt>foreign_key</tt> - foreign key used to relate the versioned model to the original model (default: page_id in the above example) | |
| 80 | - # * <tt>inheritance_column</tt> - name of the column to save the model's inheritance_column value for STI. (default: versioned_type) | |
| 81 | - # * <tt>version_column</tt> - name of the column in the model that keeps the version number (default: version) | |
| 82 | - # * <tt>sequence_name</tt> - name of the custom sequence to be used by the versioned model. | |
| 83 | - # * <tt>limit</tt> - number of revisions to keep, defaults to unlimited | |
| 84 | - # * <tt>if</tt> - symbol of method to check before saving a new version. If this method returns false, a new version is not saved. | |
| 85 | - # For finer control, pass either a Proc or modify Model#version_condition_met? | |
| 86 | - # | |
| 87 | - # acts_as_versioned :if => Proc.new { |auction| !auction.expired? } | |
| 88 | - # | |
| 89 | - # or... | |
| 90 | - # | |
| 91 | - # class Auction | |
| 92 | - # def version_condition_met? # totally bypasses the <tt>:if</tt> option | |
| 93 | - # !expired? | |
| 94 | - # end | |
| 95 | - # end | |
| 96 | - # | |
| 97 | - # * <tt>if_changed</tt> - Simple way of specifying attributes that are required to be changed before saving a model. This takes | |
| 98 | - # either a symbol or array of symbols. | |
| 99 | - # | |
| 100 | - # * <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 | |
| 101 | - # to create an anonymous mixin: | |
| 102 | - # | |
| 103 | - # class Auction | |
| 104 | - # acts_as_versioned do | |
| 105 | - # def started? | |
| 106 | - # !started_at.nil? | |
| 107 | - # end | |
| 108 | - # end | |
| 109 | - # end | |
| 110 | - # | |
| 111 | - # or... | |
| 112 | - # | |
| 113 | - # module AuctionExtension | |
| 114 | - # def started? | |
| 115 | - # !started_at.nil? | |
| 116 | - # end | |
| 117 | - # end | |
| 118 | - # class Auction | |
| 119 | - # acts_as_versioned :extend => AuctionExtension | |
| 120 | - # end | |
| 121 | - # | |
| 122 | - # Example code: | |
| 123 | - # | |
| 124 | - # @auction = Auction.find(1) | |
| 125 | - # @auction.started? | |
| 126 | - # @auction.versions.first.started? | |
| 127 | - # | |
| 128 | - # == Database Schema | |
| 129 | - # | |
| 130 | - # The model that you're versioning needs to have a 'version' attribute. The model is versioned | |
| 131 | - # into a table called #{model}_versions where the model name is singlular. The _versions table should | |
| 132 | - # contain all the fields you want versioned, the same version column, and a #{model}_id foreign key field. | |
| 133 | - # | |
| 134 | - # A lock_version field is also accepted if your model uses Optimistic Locking. If your table uses Single Table inheritance, | |
| 135 | - # then that field is reflected in the versioned model as 'versioned_type' by default. | |
| 136 | - # | |
| 137 | - # Acts_as_versioned comes prepared with the ActiveRecord::Acts::Versioned::ActMethods::ClassMethods#create_versioned_table | |
| 138 | - # method, perfect for a migration. It will also create the version column if the main model does not already have it. | |
| 139 | - # | |
| 140 | - # class AddVersions < ActiveRecord::Migration | |
| 141 | - # def self.up | |
| 142 | - # # create_versioned_table takes the same options hash | |
| 143 | - # # that create_table does | |
| 144 | - # Post.create_versioned_table | |
| 145 | - # end | |
| 146 | - # | |
| 147 | - # def self.down | |
| 148 | - # Post.drop_versioned_table | |
| 149 | - # end | |
| 150 | - # end | |
| 151 | - # | |
| 152 | - # == Changing What Fields Are Versioned | |
| 153 | - # | |
| 154 | - # By default, acts_as_versioned will version all but these fields: | |
| 155 | - # | |
| 156 | - # [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column] | |
| 157 | - # | |
| 158 | - # You can add or change those by modifying #non_versioned_columns. Note that this takes strings and not symbols. | |
| 159 | - # | |
| 160 | - # class Post < ActiveRecord::Base | |
| 161 | - # acts_as_versioned | |
| 162 | - # self.non_versioned_columns << 'comments_count' | |
| 163 | - # end | |
| 164 | - # | |
| 165 | - def acts_as_versioned(options = {}, &extension) | |
| 166 | - # don't allow multiple calls | |
| 167 | - return if self.included_modules.include?(ActiveRecord::Acts::Versioned::ActMethods) | |
| 168 | - | |
| 169 | - send :include, ActiveRecord::Acts::Versioned::ActMethods | |
| 170 | - | |
| 171 | - cattr_accessor :versioned_class_name, :versioned_foreign_key, :versioned_table_name, :versioned_inheritance_column, | |
| 172 | - :version_column, :max_version_limit, :track_altered_attributes, :version_condition, :version_sequence_name, :non_versioned_columns, | |
| 173 | - :version_association_options, :version_if_changed | |
| 174 | - | |
| 175 | - self.versioned_class_name = options[:class_name] || "Version" | |
| 176 | - self.versioned_foreign_key = options[:foreign_key] || self.to_s.foreign_key | |
| 177 | - self.versioned_table_name = options[:table_name] || "#{table_name_prefix}#{base_class.name.demodulize.underscore}_versions#{table_name_suffix}" | |
| 178 | - self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}" | |
| 179 | - self.version_column = options[:version_column] || 'version' | |
| 180 | - self.version_sequence_name = options[:sequence_name] | |
| 181 | - self.max_version_limit = options[:limit].to_i | |
| 182 | - self.version_condition = options[:if] || true | |
| 183 | - 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) | |
| 184 | - self.version_association_options = { | |
| 185 | - :class_name => "#{self.to_s}::#{versioned_class_name}", | |
| 186 | - :foreign_key => versioned_foreign_key, | |
| 187 | - :dependent => :delete_all | |
| 188 | - }.merge(options[:association_options] || {}) | |
| 189 | - | |
| 190 | - if block_given? | |
| 191 | - extension_module_name = "#{versioned_class_name}Extension" | |
| 192 | - silence_warnings do | |
| 193 | - self.const_set(extension_module_name, Module.new(&extension)) | |
| 194 | - end | |
| 195 | - | |
| 196 | - options[:extend] = self.const_get(extension_module_name) | |
| 73 | + # == Configuration options | |
| 74 | + # | |
| 75 | + # * <tt>class_name</tt> - versioned model class name (default: PageVersion in the above example) | |
| 76 | + # * <tt>table_name</tt> - versioned model table name (default: page_versions in the above example) | |
| 77 | + # * <tt>foreign_key</tt> - foreign key used to relate the versioned model to the original model (default: page_id in the above example) | |
| 78 | + # * <tt>inheritance_column</tt> - name of the column to save the model's inheritance_column value for STI. (default: versioned_type) | |
| 79 | + # * <tt>version_column</tt> - name of the column in the model that keeps the version number (default: version) | |
| 80 | + # * <tt>sequence_name</tt> - name of the custom sequence to be used by the versioned model. | |
| 81 | + # * <tt>limit</tt> - number of revisions to keep, defaults to unlimited | |
| 82 | + # * <tt>if</tt> - symbol of method to check before saving a new version. If this method returns false, a new version is not saved. | |
| 83 | + # For finer control, pass either a Proc or modify Model#version_condition_met? | |
| 84 | + # | |
| 85 | + # acts_as_versioned :if => Proc.new { |auction| !auction.expired? } | |
| 86 | + # | |
| 87 | + # or... | |
| 88 | + # | |
| 89 | + # class Auction | |
| 90 | + # def version_condition_met? # totally bypasses the <tt>:if</tt> option | |
| 91 | + # !expired? | |
| 92 | + # end | |
| 93 | + # end | |
| 94 | + # | |
| 95 | + # * <tt>if_changed</tt> - Simple way of specifying attributes that are required to be changed before saving a model. This takes | |
| 96 | + # either a symbol or array of symbols. | |
| 97 | + # | |
| 98 | + # * <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 | |
| 99 | + # to create an anonymous mixin: | |
| 100 | + # | |
| 101 | + # class Auction | |
| 102 | + # acts_as_versioned do | |
| 103 | + # def started? | |
| 104 | + # !started_at.nil? | |
| 105 | + # end | |
| 106 | + # end | |
| 107 | + # end | |
| 108 | + # | |
| 109 | + # or... | |
| 110 | + # | |
| 111 | + # module AuctionExtension | |
| 112 | + # def started? | |
| 113 | + # !started_at.nil? | |
| 114 | + # end | |
| 115 | + # end | |
| 116 | + # class Auction | |
| 117 | + # acts_as_versioned :extend => AuctionExtension | |
| 118 | + # end | |
| 119 | + # | |
| 120 | + # Example code: | |
| 121 | + # | |
| 122 | + # @auction = Auction.find(1) | |
| 123 | + # @auction.started? | |
| 124 | + # @auction.versions.first.started? | |
| 125 | + # | |
| 126 | + # == Database Schema | |
| 127 | + # | |
| 128 | + # The model that you're versioning needs to have a 'version' attribute. The model is versioned | |
| 129 | + # into a table called #{model}_versions where the model name is singlular. The _versions table should | |
| 130 | + # contain all the fields you want versioned, the same version column, and a #{model}_id foreign key field. | |
| 131 | + # | |
| 132 | + # A lock_version field is also accepted if your model uses Optimistic Locking. If your table uses Single Table inheritance, | |
| 133 | + # then that field is reflected in the versioned model as 'versioned_type' by default. | |
| 134 | + # | |
| 135 | + # Acts_as_versioned comes prepared with the ActiveRecord::Acts::Versioned::ActMethods::ClassMethods#create_versioned_table | |
| 136 | + # method, perfect for a migration. It will also create the version column if the main model does not already have it. | |
| 137 | + # | |
| 138 | + # class AddVersions < ActiveRecord::Migration | |
| 139 | + # def self.up | |
| 140 | + # # create_versioned_table takes the same options hash | |
| 141 | + # # that create_table does | |
| 142 | + # Post.create_versioned_table | |
| 143 | + # end | |
| 144 | + # | |
| 145 | + # def self.down | |
| 146 | + # Post.drop_versioned_table | |
| 147 | + # end | |
| 148 | + # end | |
| 149 | + # | |
| 150 | + # == Changing What Fields Are Versioned | |
| 151 | + # | |
| 152 | + # By default, acts_as_versioned will version all but these fields: | |
| 153 | + # | |
| 154 | + # [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column] | |
| 155 | + # | |
| 156 | + # You can add or change those by modifying #non_versioned_columns. Note that this takes strings and not symbols. | |
| 157 | + # | |
| 158 | + # class Post < ActiveRecord::Base | |
| 159 | + # acts_as_versioned | |
| 160 | + # self.non_versioned_columns << 'comments_count' | |
| 161 | + # end | |
| 162 | + # | |
| 163 | + def acts_as_versioned(options = {}, &extension) | |
| 164 | + # don't allow multiple calls | |
| 165 | + return if self.included_modules.include?(ActiveRecord::Acts::Versioned::Behaviors) | |
| 166 | + | |
| 167 | + cattr_accessor :versioned_class_name, :versioned_foreign_key, :versioned_table_name, :versioned_inheritance_column, | |
| 168 | + :version_column, :max_version_limit, :track_altered_attributes, :version_condition, :version_sequence_name, :non_versioned_columns, | |
| 169 | + :version_association_options, :version_if_changed, :version_except_columns | |
| 170 | + | |
| 171 | + self.versioned_class_name = options[:class_name] || "Version" | |
| 172 | + self.versioned_foreign_key = options[:foreign_key] || self.to_s.foreign_key | |
| 173 | + self.versioned_table_name = options[:table_name] || "#{table_name_prefix}#{base_class.name.demodulize.underscore}_versions#{table_name_suffix}" | |
| 174 | + self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}" | |
| 175 | + self.version_column = options[:version_column] || 'version' | |
| 176 | + self.version_sequence_name = options[:sequence_name] | |
| 177 | + self.max_version_limit = options[:limit].to_i | |
| 178 | + self.version_condition = options[:if] || true | |
| 179 | + self.version_except_columns = [options[:except]].flatten.map(&:to_s) #these columns are kept in _versioned, but changing them does not excplitly cause a version change | |
| 180 | + self.non_versioned_columns = [self.primary_key, inheritance_column, self.version_column, 'lock_version', versioned_inheritance_column] #these columns are excluded from _versions, and changing them does not cause a version change | |
| 181 | + self.version_association_options = { | |
| 182 | + :class_name => "#{self.to_s}::#{versioned_class_name}", | |
| 183 | + :foreign_key => versioned_foreign_key, | |
| 184 | + :dependent => :delete_all | |
| 185 | + }.merge(options[:association_options] || {}) | |
| 186 | + | |
| 187 | + if block_given? | |
| 188 | + extension_module_name = "#{versioned_class_name}Extension" | |
| 189 | + silence_warnings do | |
| 190 | + self.const_set(extension_module_name, Module.new(&extension)) | |
| 197 | 191 | end |
| 198 | 192 | |
| 199 | - class_eval <<-CLASS_METHODS | |
| 200 | - has_many :versions, version_association_options do | |
| 201 | - # finds earliest version of this record | |
| 202 | - def earliest | |
| 203 | - @earliest ||= find(:first, :order => '#{version_column}') | |
| 204 | - end | |
| 193 | + options[:extend] = self.const_get(extension_module_name) | |
| 194 | + end | |
| 205 | 195 | |
| 206 | - # find latest version of this record | |
| 207 | - def latest | |
| 208 | - @latest ||= find(:first, :order => '#{version_column} desc') | |
| 209 | - end | |
| 210 | - end | |
| 211 | - before_save :set_new_version | |
| 212 | - after_save :save_version | |
| 213 | - after_save :clear_old_versions | |
| 214 | - | |
| 215 | - unless options[:if_changed].nil? | |
| 216 | - self.track_altered_attributes = true | |
| 217 | - options[:if_changed] = [options[:if_changed]] unless options[:if_changed].is_a?(Array) | |
| 218 | - self.version_if_changed = options[:if_changed].map(&:to_s) | |
| 219 | - end | |
| 196 | + unless options[:if_changed].nil? | |
| 197 | + self.track_altered_attributes = true | |
| 198 | + options[:if_changed] = [options[:if_changed]] unless options[:if_changed].is_a?(Array) | |
| 199 | + self.version_if_changed = options[:if_changed].map(&:to_s) | |
| 200 | + end | |
| 220 | 201 | |
| 221 | - include options[:extend] if options[:extend].is_a?(Module) | |
| 222 | - CLASS_METHODS | |
| 202 | + include options[:extend] if options[:extend].is_a?(Module) | |
| 223 | 203 | |
| 224 | - # create the dynamic versioned model | |
| 225 | - const_set(versioned_class_name, Class.new(ActiveRecord::Base)).class_eval do | |
| 226 | - def self.reloadable? ; false ; end | |
| 227 | - # find first version before the given version | |
| 228 | - def self.before(version) | |
| 229 | - find :first, :order => 'version desc', | |
| 230 | - :conditions => ["#{original_class.versioned_foreign_key} = ? and version < ?", version.send(original_class.versioned_foreign_key), version.version] | |
| 231 | - end | |
| 204 | + include ActiveRecord::Acts::Versioned::Behaviors | |
| 232 | 205 | |
| 233 | - # find first version after the given version. | |
| 234 | - def self.after(version) | |
| 235 | - find :first, :order => 'version', | |
| 236 | - :conditions => ["#{original_class.versioned_foreign_key} = ? and version > ?", version.send(original_class.versioned_foreign_key), version.version] | |
| 237 | - end | |
| 206 | + # | |
| 207 | + # Create the dynamic versioned model | |
| 208 | + # | |
| 209 | + const_set(versioned_class_name, Class.new(ActiveRecord::Base)).class_eval do | |
| 210 | + def self.reloadable?; | |
| 211 | + false; | |
| 212 | + end | |
| 238 | 213 | |
| 239 | - def previous | |
| 240 | - self.class.before(self) | |
| 241 | - end | |
| 214 | + # find first version before the given version | |
| 215 | + def self.before(version) | |
| 216 | + where(["#{original_class.versioned_foreign_key} = ? and version < ?", version.send(original_class.versioned_foreign_key), version.version]). | |
| 217 | + order('version DESC'). | |
| 218 | + first | |
| 219 | + end | |
| 242 | 220 | |
| 243 | - def next | |
| 244 | - self.class.after(self) | |
| 245 | - end | |
| 221 | + # find first version after the given version. | |
| 222 | + def self.after(version) | |
| 223 | + where(["#{original_class.versioned_foreign_key} = ? and version > ?", version.send(original_class.versioned_foreign_key), version.version]). | |
| 224 | + order('version ASC'). | |
| 225 | + first | |
| 226 | + end | |
| 246 | 227 | |
| 247 | - def versions_count | |
| 248 | - page.version | |
| 249 | - end | |
| 228 | + # finds earliest version of this record | |
| 229 | + def self.earliest | |
| 230 | + order("#{original_class.version_column}").first | |
| 231 | + end | |
| 232 | + | |
| 233 | + # find latest version of this record | |
| 234 | + def self.latest | |
| 235 | + order("#{original_class.version_column} desc").first | |
| 236 | + end | |
| 237 | + | |
| 238 | + def previous | |
| 239 | + self.class.before(self) | |
| 240 | + end | |
| 241 | + | |
| 242 | + def next | |
| 243 | + self.class.after(self) | |
| 250 | 244 | end |
| 251 | 245 | |
| 252 | - versioned_class.cattr_accessor :original_class | |
| 253 | - versioned_class.original_class = self | |
| 254 | - versioned_class.set_table_name versioned_table_name | |
| 255 | - versioned_class.belongs_to self.to_s.demodulize.underscore.to_sym, | |
| 256 | - :class_name => "::#{self.to_s}", | |
| 257 | - :foreign_key => versioned_foreign_key | |
| 258 | - versioned_class.send :include, options[:extend] if options[:extend].is_a?(Module) | |
| 259 | - versioned_class.set_sequence_name version_sequence_name if version_sequence_name | |
| 246 | + def versions_count | |
| 247 | + page.version | |
| 248 | + end | |
| 260 | 249 | end |
| 250 | + | |
| 251 | + versioned_class.cattr_accessor :original_class | |
| 252 | + versioned_class.original_class = self | |
| 253 | + versioned_class.table_name = versioned_table_name | |
| 254 | + versioned_class.belongs_to self.to_s.demodulize.underscore.to_sym, | |
| 255 | + :class_name => "::#{self.to_s}", | |
| 256 | + :foreign_key => versioned_foreign_key | |
| 257 | + versioned_class.send :include, options[:extend] if options[:extend].is_a?(Module) | |
| 258 | + versioned_class.set_sequence_name version_sequence_name if version_sequence_name | |
| 261 | 259 | end |
| 262 | 260 | |
| 263 | - module ActMethods | |
| 264 | - def self.included(base) # :nodoc: | |
| 265 | - base.extend ClassMethods | |
| 261 | + module Behaviors | |
| 262 | + extend ActiveSupport::Concern | |
| 263 | + | |
| 264 | + included do | |
| 265 | + has_many :versions, self.version_association_options | |
| 266 | + | |
| 267 | + before_save :set_new_version | |
| 268 | + after_save :save_version | |
| 269 | + after_save :clear_old_versions | |
| 266 | 270 | end |
| 267 | 271 | |
| 268 | 272 | # Saves a version of the model in the versioned table. This is called in the after_save callback by default |
| ... | ... | @@ -292,7 +296,7 @@ module ActiveRecord #:nodoc: |
| 292 | 296 | if version.is_a?(self.class.versioned_class) |
| 293 | 297 | return false unless version.send(self.class.versioned_foreign_key) == id and !version.new_record? |
| 294 | 298 | else |
| 295 | - return false unless version = versions.send("find_by_#{self.class.version_column}", version) | |
| 299 | + return false unless version = versions.where(self.class.version_column => version).first | |
| 296 | 300 | end |
| 297 | 301 | self.clone_versioned_model(version, self) |
| 298 | 302 | send("#{self.class.version_column}=", version.send(self.class.version_column)) |
| ... | ... | @@ -320,23 +324,33 @@ module ActiveRecord #:nodoc: |
| 320 | 324 | end |
| 321 | 325 | end |
| 322 | 326 | end |
| 323 | - | |
| 327 | + | |
| 324 | 328 | def altered? |
| 325 | - track_altered_attributes ? (version_if_changed - changed).length < version_if_changed.length : changed? | |
| 329 | + changed.map { |c| self.class.versioned_columns.map(&:name).include?(c) & !self.class.version_except_columns.include?(c) }.any? | |
| 326 | 330 | end |
| 327 | 331 | |
| 328 | 332 | # Clones a model. Used when saving a new version or reverting a model's version. |
| 329 | 333 | def clone_versioned_model(orig_model, new_model) |
| 330 | 334 | self.class.versioned_columns.each do |col| |
| 331 | - new_model.send("#{col.name}=", orig_model.send(col.name)) if orig_model.has_attribute?(col.name) | |
| 335 | + next unless orig_model.has_attribute?(col.name) | |
| 336 | + define_method(new_model, col.name.to_sym) | |
| 337 | + new_model.send("#{col.name.to_sym}=", orig_model.send(col.name)) | |
| 332 | 338 | end |
| 333 | 339 | |
| 334 | 340 | if orig_model.is_a?(self.class.versioned_class) |
| 335 | 341 | new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column] |
| 336 | 342 | elsif new_model.is_a?(self.class.versioned_class) |
| 337 | - new_model[self.class.versioned_inheritance_column] = orig_model[orig_model.class.inheritance_column] | |
| 343 | + sym = self.class.versioned_inheritance_column.to_sym | |
| 344 | + define_method new_model, sym | |
| 345 | + new_model.send("#{sym}=", orig_model[orig_model.class.inheritance_column]) if orig_model[orig_model.class.inheritance_column] | |
| 338 | 346 | end |
| 339 | 347 | end |
| 348 | + | |
| 349 | + def define_method(object, method) | |
| 350 | + return if object.methods.include? method | |
| 351 | + metaclass = class << object; self; end | |
| 352 | + metaclass.send :attr_accessor, method | |
| 353 | + end | |
| 340 | 354 | |
| 341 | 355 | # Checks whether a new version shall be saved or not. Calls <tt>version_condition_met?</tt> and <tt>changed?</tt>. |
| 342 | 356 | def save_version? |
| ... | ... | @@ -347,12 +361,12 @@ module ActiveRecord #:nodoc: |
| 347 | 361 | # custom version condition checking. |
| 348 | 362 | def version_condition_met? |
| 349 | 363 | case |
| 350 | - when version_condition.is_a?(Symbol) | |
| 351 | - send(version_condition) | |
| 352 | - when version_condition.respond_to?(:call) && (version_condition.arity == 1 || version_condition.arity == -1) | |
| 353 | - version_condition.call(self) | |
| 354 | - else | |
| 355 | - version_condition | |
| 364 | + when version_condition.is_a?(Symbol) | |
| 365 | + send(version_condition) | |
| 366 | + when version_condition.respond_to?(:call) && (version_condition.arity == 1 || version_condition.arity == -1) | |
| 367 | + version_condition.call(self) | |
| 368 | + else | |
| 369 | + version_condition | |
| 356 | 370 | end |
| 357 | 371 | end |
| 358 | 372 | |
| ... | ... | @@ -376,19 +390,23 @@ module ActiveRecord #:nodoc: |
| 376 | 390 | self.class.without_locking(&block) |
| 377 | 391 | end |
| 378 | 392 | |
| 379 | - def empty_callback() end #:nodoc: | |
| 393 | + def empty_callback() | |
| 394 | + end | |
| 395 | + | |
| 396 | + #:nodoc: | |
| 380 | 397 | |
| 381 | 398 | protected |
| 382 | - # sets the new version before saving, unless you're using optimistic locking. In that case, let it take care of the version. | |
| 383 | - def set_new_version | |
| 384 | - @saving_version = new_record? || save_version? | |
| 385 | - self.send("#{self.class.version_column}=", next_version) if new_record? || (!locking_enabled? && save_version?) | |
| 386 | - end | |
| 399 | + # sets the new version before saving, unless you're using optimistic locking. In that case, let it take care of the version. | |
| 400 | + def set_new_version | |
| 401 | + @saving_version = new_record? || save_version? | |
| 402 | + self.send("#{self.class.version_column}=", next_version) if new_record? || (!locking_enabled? && save_version?) | |
| 403 | + end | |
| 404 | + | |
| 405 | + # Gets the next available version for the current record, or 1 for a new record | |
| 406 | + def next_version | |
| 407 | + (new_record? ? 0 : versions.calculate(:maximum, version_column).to_i) + 1 | |
| 408 | + end | |
| 387 | 409 | |
| 388 | - # Gets the next available version for the current record, or 1 for a new record | |
| 389 | - def next_version | |
| 390 | - (new_record? ? 0 : versions.calculate(:max, version_column).to_i) + 1 | |
| 391 | - end | |
| 392 | 410 | |
| 393 | 411 | module ClassMethods |
| 394 | 412 | # Returns an array of columns that are versioned. See non_versioned_columns |
| ... | ... | @@ -410,28 +428,28 @@ module ActiveRecord #:nodoc: |
| 410 | 428 | end |
| 411 | 429 | |
| 412 | 430 | return if connection.table_exists?(versioned_table_name) |
| 413 | - | |
| 431 | + | |
| 414 | 432 | self.connection.create_table(versioned_table_name, create_table_options) do |t| |
| 415 | 433 | t.column versioned_foreign_key, :integer |
| 416 | 434 | t.column version_column, :integer |
| 417 | 435 | end |
| 418 | 436 | |
| 419 | - self.versioned_columns.each do |col| | |
| 420 | - self.connection.add_column versioned_table_name, col.name, col.type, | |
| 421 | - :limit => col.limit, | |
| 422 | - :default => col.default, | |
| 423 | - :scale => col.scale, | |
| 424 | - :precision => col.precision | |
| 437 | + self.versioned_columns.each do |col| | |
| 438 | + self.connection.add_column versioned_table_name, col.name, col.type, | |
| 439 | + :limit => col.limit, | |
| 440 | + :default => col.default, | |
| 441 | + :scale => col.scale, | |
| 442 | + :precision => col.precision | |
| 425 | 443 | end |
| 426 | 444 | |
| 427 | 445 | if type_col = self.columns_hash[inheritance_column] |
| 428 | - self.connection.add_column versioned_table_name, versioned_inheritance_column, type_col.type, | |
| 429 | - :limit => type_col.limit, | |
| 430 | - :default => type_col.default, | |
| 431 | - :scale => type_col.scale, | |
| 432 | - :precision => type_col.precision | |
| 446 | + self.connection.add_column versioned_table_name, versioned_inheritance_column, type_col.type, | |
| 447 | + :limit => type_col.limit, | |
| 448 | + :default => type_col.default, | |
| 449 | + :scale => type_col.scale, | |
| 450 | + :precision => type_col.precision | |
| 433 | 451 | end |
| 434 | - | |
| 452 | + | |
| 435 | 453 | self.connection.add_index versioned_table_name, versioned_foreign_key |
| 436 | 454 | end |
| 437 | 455 | |
| ... | ... | @@ -447,7 +465,7 @@ module ActiveRecord #:nodoc: |
| 447 | 465 | # end |
| 448 | 466 | # |
| 449 | 467 | def without_revision(&block) |
| 450 | - class_eval do | |
| 468 | + class_eval do | |
| 451 | 469 | CALLBACKS.each do |attr_name| |
| 452 | 470 | alias_method "orig_#{attr_name}".to_sym, attr_name |
| 453 | 471 | alias_method attr_name, :empty_callback |
| ... | ... | @@ -455,7 +473,7 @@ module ActiveRecord #:nodoc: |
| 455 | 473 | end |
| 456 | 474 | block.call |
| 457 | 475 | ensure |
| 458 | - class_eval do | |
| 476 | + class_eval do | |
| 459 | 477 | CALLBACKS.each do |attr_name| |
| 460 | 478 | alias_method attr_name, "orig_#{attr_name}".to_sym |
| 461 | 479 | end |
| ... | ... | @@ -483,4 +501,4 @@ module ActiveRecord #:nodoc: |
| 483 | 501 | end |
| 484 | 502 | end |
| 485 | 503 | |
| 486 | -ActiveRecord::Base.send :include, ActiveRecord::Acts::Versioned | |
| 504 | +ActiveRecord::Base.extend ActiveRecord::Acts::Versioned | ... | ... |
vendor/plugins/acts_as_versioned/test/abstract_unit.rb
| ... | ... | @@ -1,48 +0,0 @@ |
| 1 | -$:.unshift(File.dirname(__FILE__) + '/../../../rails/activesupport/lib') | |
| 2 | -$:.unshift(File.dirname(__FILE__) + '/../../../rails/activerecord/lib') | |
| 3 | -$:.unshift(File.dirname(__FILE__) + '/../lib') | |
| 4 | -require 'test/unit' | |
| 5 | -begin | |
| 6 | - require 'active_support' | |
| 7 | - require 'active_record' | |
| 8 | - require 'active_record/fixtures' | |
| 9 | -rescue LoadError | |
| 10 | - require 'rubygems' | |
| 11 | - retry | |
| 12 | -end | |
| 13 | - | |
| 14 | -begin | |
| 15 | - require 'ruby-debug' | |
| 16 | - Debugger.start | |
| 17 | -rescue LoadError | |
| 18 | -end | |
| 19 | - | |
| 20 | -require 'acts_as_versioned' | |
| 21 | - | |
| 22 | -config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml')) | |
| 23 | -ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log") | |
| 24 | -ActiveRecord::Base.configurations = {'test' => config[ENV['DB'] || 'sqlite3']} | |
| 25 | -ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test']) | |
| 26 | - | |
| 27 | -load(File.dirname(__FILE__) + "/schema.rb") | |
| 28 | - | |
| 29 | -# set up custom sequence on widget_versions for DBs that support sequences | |
| 30 | -if ENV['DB'] == 'postgresql' | |
| 31 | - ActiveRecord::Base.connection.execute "DROP SEQUENCE widgets_seq;" rescue nil | |
| 32 | - ActiveRecord::Base.connection.remove_column :widget_versions, :id | |
| 33 | - ActiveRecord::Base.connection.execute "CREATE SEQUENCE widgets_seq START 101;" | |
| 34 | - ActiveRecord::Base.connection.execute "ALTER TABLE widget_versions ADD COLUMN id INTEGER PRIMARY KEY DEFAULT nextval('widgets_seq');" | |
| 35 | -end | |
| 36 | - | |
| 37 | -Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/" | |
| 38 | -$:.unshift(Test::Unit::TestCase.fixture_path) | |
| 39 | - | |
| 40 | -class Test::Unit::TestCase #:nodoc: | |
| 41 | - # Turn off transactional fixtures if you're working with MyISAM tables in MySQL | |
| 42 | - self.use_transactional_fixtures = true | |
| 43 | - | |
| 44 | - # Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david) | |
| 45 | - self.use_instantiated_fixtures = false | |
| 46 | - | |
| 47 | - # Add more helper methods to be used by all tests here... | |
| 48 | -end | |
| 49 | 0 | \ No newline at end of file |
vendor/plugins/acts_as_versioned/test/database.yml
| ... | ... | @@ -1,18 +0,0 @@ |
| 1 | -sqlite: | |
| 2 | - :adapter: sqlite | |
| 3 | - :dbfile: acts_as_versioned_plugin.sqlite.db | |
| 4 | -sqlite3: | |
| 5 | - :adapter: sqlite3 | |
| 6 | - :dbfile: acts_as_versioned_plugin.sqlite3.db | |
| 7 | -postgresql: | |
| 8 | - :adapter: postgresql | |
| 9 | - :username: postgres | |
| 10 | - :password: postgres | |
| 11 | - :database: acts_as_versioned_plugin_test | |
| 12 | - :min_messages: ERROR | |
| 13 | -mysql: | |
| 14 | - :adapter: mysql | |
| 15 | - :host: localhost | |
| 16 | - :username: rails | |
| 17 | - :password: | |
| 18 | - :database: acts_as_versioned_plugin_test | |
| 19 | 0 | \ No newline at end of file |
vendor/plugins/acts_as_versioned/test/fixtures/authors.yml
vendor/plugins/acts_as_versioned/test/fixtures/landmark.rb
vendor/plugins/acts_as_versioned/test/fixtures/landmark_versions.yml
vendor/plugins/acts_as_versioned/test/fixtures/landmarks.yml
vendor/plugins/acts_as_versioned/test/fixtures/locked_pages.yml
vendor/plugins/acts_as_versioned/test/fixtures/locked_pages_revisions.yml
| ... | ... | @@ -1,27 +0,0 @@ |
| 1 | -welcome_1: | |
| 2 | - id: 1 | |
| 3 | - page_id: 1 | |
| 4 | - title: Welcome to the weblg | |
| 5 | - lock_version: 23 | |
| 6 | - version_type: LockedPage | |
| 7 | - | |
| 8 | -welcome_2: | |
| 9 | - id: 2 | |
| 10 | - page_id: 1 | |
| 11 | - title: Welcome to the weblog | |
| 12 | - lock_version: 24 | |
| 13 | - version_type: LockedPage | |
| 14 | - | |
| 15 | -thinking_1: | |
| 16 | - id: 3 | |
| 17 | - page_id: 2 | |
| 18 | - title: So I was thinking!!! | |
| 19 | - lock_version: 23 | |
| 20 | - version_type: SpecialLockedPage | |
| 21 | - | |
| 22 | -thinking_2: | |
| 23 | - id: 4 | |
| 24 | - page_id: 2 | |
| 25 | - title: So I was thinking | |
| 26 | - lock_version: 24 | |
| 27 | - version_type: SpecialLockedPage |
vendor/plugins/acts_as_versioned/test/fixtures/migrations/1_add_versioned_tables.rb
| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | -class AddVersionedTables < ActiveRecord::Migration | |
| 2 | - def self.up | |
| 3 | - create_table("things") do |t| | |
| 4 | - t.column :title, :text | |
| 5 | - t.column :price, :decimal, :precision => 7, :scale => 2 | |
| 6 | - t.column :type, :string | |
| 7 | - end | |
| 8 | - Thing.create_versioned_table | |
| 9 | - end | |
| 10 | - | |
| 11 | - def self.down | |
| 12 | - Thing.drop_versioned_table | |
| 13 | - drop_table "things" rescue nil | |
| 14 | - end | |
| 15 | -end | |
| 16 | 0 | \ No newline at end of file |
vendor/plugins/acts_as_versioned/test/fixtures/page.rb
| ... | ... | @@ -1,43 +0,0 @@ |
| 1 | -class Page < ActiveRecord::Base | |
| 2 | - belongs_to :author | |
| 3 | - has_many :authors, :through => :versions, :order => 'name' | |
| 4 | - belongs_to :revisor, :class_name => 'Author' | |
| 5 | - has_many :revisors, :class_name => 'Author', :through => :versions, :order => 'name' | |
| 6 | - acts_as_versioned :if => :feeling_good? do | |
| 7 | - def self.included(base) | |
| 8 | - base.cattr_accessor :feeling_good | |
| 9 | - base.feeling_good = true | |
| 10 | - base.belongs_to :author | |
| 11 | - base.belongs_to :revisor, :class_name => 'Author' | |
| 12 | - end | |
| 13 | - | |
| 14 | - def feeling_good? | |
| 15 | - @@feeling_good == true | |
| 16 | - end | |
| 17 | - end | |
| 18 | -end | |
| 19 | - | |
| 20 | -module LockedPageExtension | |
| 21 | - def hello_world | |
| 22 | - 'hello_world' | |
| 23 | - end | |
| 24 | -end | |
| 25 | - | |
| 26 | -class LockedPage < ActiveRecord::Base | |
| 27 | - acts_as_versioned \ | |
| 28 | - :inheritance_column => :version_type, | |
| 29 | - :foreign_key => :page_id, | |
| 30 | - :table_name => :locked_pages_revisions, | |
| 31 | - :class_name => 'LockedPageRevision', | |
| 32 | - :version_column => :lock_version, | |
| 33 | - :limit => 2, | |
| 34 | - :if_changed => :title, | |
| 35 | - :extend => LockedPageExtension | |
| 36 | -end | |
| 37 | - | |
| 38 | -class SpecialLockedPage < LockedPage | |
| 39 | -end | |
| 40 | - | |
| 41 | -class Author < ActiveRecord::Base | |
| 42 | - has_many :pages | |
| 43 | -end | |
| 44 | 0 | \ No newline at end of file |
vendor/plugins/acts_as_versioned/test/fixtures/page_versions.yml
| ... | ... | @@ -1,16 +0,0 @@ |
| 1 | -welcome_2: | |
| 2 | - id: 1 | |
| 3 | - page_id: 1 | |
| 4 | - title: Welcome to the weblog | |
| 5 | - body: Such a lovely day | |
| 6 | - version: 24 | |
| 7 | - author_id: 1 | |
| 8 | - revisor_id: 1 | |
| 9 | -welcome_1: | |
| 10 | - id: 2 | |
| 11 | - page_id: 1 | |
| 12 | - title: Welcome to the weblg | |
| 13 | - body: Such a lovely day | |
| 14 | - version: 23 | |
| 15 | - author_id: 2 | |
| 16 | - revisor_id: 2 |
vendor/plugins/acts_as_versioned/test/fixtures/pages.yml
vendor/plugins/acts_as_versioned/test/fixtures/widget.rb
vendor/plugins/acts_as_versioned/test/migration_test.rb
| ... | ... | @@ -1,46 +0,0 @@ |
| 1 | -require File.join(File.dirname(__FILE__), 'abstract_unit') | |
| 2 | - | |
| 3 | -if ActiveRecord::Base.connection.supports_migrations? | |
| 4 | - class Thing < ActiveRecord::Base | |
| 5 | - attr_accessor :version | |
| 6 | - acts_as_versioned | |
| 7 | - end | |
| 8 | - | |
| 9 | - class MigrationTest < Test::Unit::TestCase | |
| 10 | - self.use_transactional_fixtures = false | |
| 11 | - def teardown | |
| 12 | - if ActiveRecord::Base.connection.respond_to?(:initialize_schema_information) | |
| 13 | - ActiveRecord::Base.connection.initialize_schema_information | |
| 14 | - ActiveRecord::Base.connection.update "UPDATE schema_info SET version = 0" | |
| 15 | - else | |
| 16 | - ActiveRecord::Base.connection.initialize_schema_migrations_table | |
| 17 | - ActiveRecord::Base.connection.assume_migrated_upto_version(0) | |
| 18 | - end | |
| 19 | - | |
| 20 | - Thing.connection.drop_table "things" rescue nil | |
| 21 | - Thing.connection.drop_table "thing_versions" rescue nil | |
| 22 | - Thing.reset_column_information | |
| 23 | - end | |
| 24 | - | |
| 25 | - def test_versioned_migration | |
| 26 | - assert_raises(ActiveRecord::StatementInvalid) { Thing.create :title => 'blah blah' } | |
| 27 | - # take 'er up | |
| 28 | - ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/') | |
| 29 | - t = Thing.create :title => 'blah blah', :price => 123.45, :type => 'Thing' | |
| 30 | - assert_equal 1, t.versions.size | |
| 31 | - | |
| 32 | - # check that the price column has remembered its value correctly | |
| 33 | - assert_equal t.price, t.versions.first.price | |
| 34 | - assert_equal t.title, t.versions.first.title | |
| 35 | - assert_equal t[:type], t.versions.first[:type] | |
| 36 | - | |
| 37 | - # make sure that the precision of the price column has been preserved | |
| 38 | - assert_equal 7, Thing::Version.columns.find{|c| c.name == "price"}.precision | |
| 39 | - assert_equal 2, Thing::Version.columns.find{|c| c.name == "price"}.scale | |
| 40 | - | |
| 41 | - # now lets take 'er back down | |
| 42 | - ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/') | |
| 43 | - assert_raises(ActiveRecord::StatementInvalid) { Thing.create :title => 'blah blah' } | |
| 44 | - end | |
| 45 | - end | |
| 46 | -end |
vendor/plugins/acts_as_versioned/test/schema.rb
| ... | ... | @@ -1,82 +0,0 @@ |
| 1 | -ActiveRecord::Schema.define(:version => 0) do | |
| 2 | - create_table :pages, :force => true do |t| | |
| 3 | - t.column :version, :integer | |
| 4 | - t.column :title, :string, :limit => 255 | |
| 5 | - t.column :body, :text | |
| 6 | - t.column :created_on, :datetime | |
| 7 | - t.column :updated_on, :datetime | |
| 8 | - t.column :author_id, :integer | |
| 9 | - t.column :revisor_id, :integer | |
| 10 | - end | |
| 11 | - | |
| 12 | - create_table :page_versions, :force => true do |t| | |
| 13 | - t.column :page_id, :integer | |
| 14 | - t.column :version, :integer | |
| 15 | - t.column :title, :string, :limit => 255 | |
| 16 | - t.column :body, :text | |
| 17 | - t.column :created_on, :datetime | |
| 18 | - t.column :updated_on, :datetime | |
| 19 | - t.column :author_id, :integer | |
| 20 | - t.column :revisor_id, :integer | |
| 21 | - end | |
| 22 | - | |
| 23 | - add_index :page_versions, [:page_id, :version], :unique => true | |
| 24 | - | |
| 25 | - create_table :authors, :force => true do |t| | |
| 26 | - t.column :page_id, :integer | |
| 27 | - t.column :name, :string | |
| 28 | - end | |
| 29 | - | |
| 30 | - create_table :locked_pages, :force => true do |t| | |
| 31 | - t.column :lock_version, :integer | |
| 32 | - t.column :title, :string, :limit => 255 | |
| 33 | - t.column :body, :text | |
| 34 | - t.column :type, :string, :limit => 255 | |
| 35 | - end | |
| 36 | - | |
| 37 | - create_table :locked_pages_revisions, :force => true do |t| | |
| 38 | - t.column :page_id, :integer | |
| 39 | - t.column :lock_version, :integer | |
| 40 | - t.column :title, :string, :limit => 255 | |
| 41 | - t.column :body, :text | |
| 42 | - t.column :version_type, :string, :limit => 255 | |
| 43 | - t.column :updated_at, :datetime | |
| 44 | - end | |
| 45 | - | |
| 46 | - add_index :locked_pages_revisions, [:page_id, :lock_version], :unique => true | |
| 47 | - | |
| 48 | - create_table :widgets, :force => true do |t| | |
| 49 | - t.column :name, :string, :limit => 50 | |
| 50 | - t.column :foo, :string | |
| 51 | - t.column :version, :integer | |
| 52 | - t.column :updated_at, :datetime | |
| 53 | - end | |
| 54 | - | |
| 55 | - create_table :widget_versions, :force => true do |t| | |
| 56 | - t.column :widget_id, :integer | |
| 57 | - t.column :name, :string, :limit => 50 | |
| 58 | - t.column :version, :integer | |
| 59 | - t.column :updated_at, :datetime | |
| 60 | - end | |
| 61 | - | |
| 62 | - add_index :widget_versions, [:widget_id, :version], :unique => true | |
| 63 | - | |
| 64 | - create_table :landmarks, :force => true do |t| | |
| 65 | - t.column :name, :string | |
| 66 | - t.column :latitude, :float | |
| 67 | - t.column :longitude, :float | |
| 68 | - t.column :doesnt_trigger_version,:string | |
| 69 | - t.column :version, :integer | |
| 70 | - end | |
| 71 | - | |
| 72 | - create_table :landmark_versions, :force => true do |t| | |
| 73 | - t.column :landmark_id, :integer | |
| 74 | - t.column :name, :string | |
| 75 | - t.column :latitude, :float | |
| 76 | - t.column :longitude, :float | |
| 77 | - t.column :doesnt_trigger_version,:string | |
| 78 | - t.column :version, :integer | |
| 79 | - end | |
| 80 | - | |
| 81 | - add_index :landmark_versions, [:landmark_id, :version], :unique => true | |
| 82 | -end |
vendor/plugins/acts_as_versioned/test/versioned_test.rb
| ... | ... | @@ -1,370 +0,0 @@ |
| 1 | -require File.join(File.dirname(__FILE__), 'abstract_unit') | |
| 2 | -require File.join(File.dirname(__FILE__), 'fixtures/page') | |
| 3 | -require File.join(File.dirname(__FILE__), 'fixtures/widget') | |
| 4 | - | |
| 5 | -class VersionedTest < Test::Unit::TestCase | |
| 6 | - fixtures :pages, :page_versions, :locked_pages, :locked_pages_revisions, :authors, :landmarks, :landmark_versions | |
| 7 | - set_fixture_class :page_versions => Page::Version | |
| 8 | - | |
| 9 | - def test_saves_versioned_copy | |
| 10 | - p = Page.create! :title => 'first title', :body => 'first body' | |
| 11 | - assert !p.new_record? | |
| 12 | - assert_equal 1, p.versions.size | |
| 13 | - assert_equal 1, p.version | |
| 14 | - assert_instance_of Page.versioned_class, p.versions.first | |
| 15 | - end | |
| 16 | - | |
| 17 | - def test_saves_without_revision | |
| 18 | - p = pages(:welcome) | |
| 19 | - old_versions = p.versions.count | |
| 20 | - | |
| 21 | - p.save_without_revision | |
| 22 | - | |
| 23 | - p.without_revision do | |
| 24 | - p.update_attributes :title => 'changed' | |
| 25 | - end | |
| 26 | - | |
| 27 | - assert_equal old_versions, p.versions.count | |
| 28 | - end | |
| 29 | - | |
| 30 | - def test_rollback_with_version_number | |
| 31 | - p = pages(:welcome) | |
| 32 | - assert_equal 24, p.version | |
| 33 | - assert_equal 'Welcome to the weblog', p.title | |
| 34 | - | |
| 35 | - assert p.revert_to!(23), "Couldn't revert to 23" | |
| 36 | - assert_equal 23, p.version | |
| 37 | - assert_equal 'Welcome to the weblg', p.title | |
| 38 | - end | |
| 39 | - | |
| 40 | - def test_versioned_class_name | |
| 41 | - assert_equal 'Version', Page.versioned_class_name | |
| 42 | - assert_equal 'LockedPageRevision', LockedPage.versioned_class_name | |
| 43 | - end | |
| 44 | - | |
| 45 | - def test_versioned_class | |
| 46 | - assert_equal Page::Version, Page.versioned_class | |
| 47 | - assert_equal LockedPage::LockedPageRevision, LockedPage.versioned_class | |
| 48 | - end | |
| 49 | - | |
| 50 | - def test_special_methods | |
| 51 | - assert_nothing_raised { pages(:welcome).feeling_good? } | |
| 52 | - assert_nothing_raised { pages(:welcome).versions.first.feeling_good? } | |
| 53 | - assert_nothing_raised { locked_pages(:welcome).hello_world } | |
| 54 | - assert_nothing_raised { locked_pages(:welcome).versions.first.hello_world } | |
| 55 | - end | |
| 56 | - | |
| 57 | - def test_rollback_with_version_class | |
| 58 | - p = pages(:welcome) | |
| 59 | - assert_equal 24, p.version | |
| 60 | - assert_equal 'Welcome to the weblog', p.title | |
| 61 | - | |
| 62 | - assert p.revert_to!(p.versions.find_by_version(23)), "Couldn't revert to 23" | |
| 63 | - assert_equal 23, p.version | |
| 64 | - assert_equal 'Welcome to the weblg', p.title | |
| 65 | - end | |
| 66 | - | |
| 67 | - def test_rollback_fails_with_invalid_revision | |
| 68 | - p = locked_pages(:welcome) | |
| 69 | - assert !p.revert_to!(locked_pages(:thinking)) | |
| 70 | - end | |
| 71 | - | |
| 72 | - def test_saves_versioned_copy_with_options | |
| 73 | - p = LockedPage.create! :title => 'first title' | |
| 74 | - assert !p.new_record? | |
| 75 | - assert_equal 1, p.versions.size | |
| 76 | - assert_instance_of LockedPage.versioned_class, p.versions.first | |
| 77 | - end | |
| 78 | - | |
| 79 | - def test_rollback_with_version_number_with_options | |
| 80 | - p = locked_pages(:welcome) | |
| 81 | - assert_equal 'Welcome to the weblog', p.title | |
| 82 | - assert_equal 'LockedPage', p.versions.first.version_type | |
| 83 | - | |
| 84 | - assert p.revert_to!(p.versions.first.lock_version), "Couldn't revert to 23" | |
| 85 | - assert_equal 'Welcome to the weblg', p.title | |
| 86 | - assert_equal 'LockedPage', p.versions.first.version_type | |
| 87 | - end | |
| 88 | - | |
| 89 | - def test_rollback_with_version_class_with_options | |
| 90 | - p = locked_pages(:welcome) | |
| 91 | - assert_equal 'Welcome to the weblog', p.title | |
| 92 | - assert_equal 'LockedPage', p.versions.first.version_type | |
| 93 | - | |
| 94 | - assert p.revert_to!(p.versions.first), "Couldn't revert to 1" | |
| 95 | - assert_equal 'Welcome to the weblg', p.title | |
| 96 | - assert_equal 'LockedPage', p.versions.first.version_type | |
| 97 | - end | |
| 98 | - | |
| 99 | - def test_saves_versioned_copy_with_sti | |
| 100 | - p = SpecialLockedPage.create! :title => 'first title' | |
| 101 | - assert !p.new_record? | |
| 102 | - assert_equal 1, p.versions.size | |
| 103 | - assert_instance_of LockedPage.versioned_class, p.versions.first | |
| 104 | - assert_equal 'SpecialLockedPage', p.versions.first.version_type | |
| 105 | - end | |
| 106 | - | |
| 107 | - def test_rollback_with_version_number_with_sti | |
| 108 | - p = locked_pages(:thinking) | |
| 109 | - assert_equal 'So I was thinking', p.title | |
| 110 | - | |
| 111 | - assert p.revert_to!(p.versions.first.lock_version), "Couldn't revert to 1" | |
| 112 | - assert_equal 'So I was thinking!!!', p.title | |
| 113 | - assert_equal 'SpecialLockedPage', p.versions.first.version_type | |
| 114 | - end | |
| 115 | - | |
| 116 | - def test_lock_version_works_with_versioning | |
| 117 | - p = locked_pages(:thinking) | |
| 118 | - p2 = LockedPage.find(p.id) | |
| 119 | - | |
| 120 | - p.title = 'fresh title' | |
| 121 | - p.save | |
| 122 | - assert_equal 2, p.versions.size # limit! | |
| 123 | - | |
| 124 | - assert_raises(ActiveRecord::StaleObjectError) do | |
| 125 | - p2.title = 'stale title' | |
| 126 | - p2.save | |
| 127 | - end | |
| 128 | - end | |
| 129 | - | |
| 130 | - def test_version_if_condition | |
| 131 | - p = Page.create! :title => "title" | |
| 132 | - assert_equal 1, p.version | |
| 133 | - | |
| 134 | - Page.feeling_good = false | |
| 135 | - p.save | |
| 136 | - assert_equal 1, p.version | |
| 137 | - Page.feeling_good = true | |
| 138 | - end | |
| 139 | - | |
| 140 | - def test_version_if_condition2 | |
| 141 | - # set new if condition | |
| 142 | - Page.class_eval do | |
| 143 | - def new_feeling_good() title[0..0] == 'a'; end | |
| 144 | - alias_method :old_feeling_good, :feeling_good? | |
| 145 | - alias_method :feeling_good?, :new_feeling_good | |
| 146 | - end | |
| 147 | - | |
| 148 | - p = Page.create! :title => "title" | |
| 149 | - assert_equal 1, p.version # version does not increment | |
| 150 | - assert_equal 1, p.versions.count | |
| 151 | - | |
| 152 | - p.update_attributes(:title => 'new title') | |
| 153 | - assert_equal 1, p.version # version does not increment | |
| 154 | - assert_equal 1, p.versions.count | |
| 155 | - | |
| 156 | - p.update_attributes(:title => 'a title') | |
| 157 | - assert_equal 2, p.version | |
| 158 | - assert_equal 2, p.versions.count | |
| 159 | - | |
| 160 | - # reset original if condition | |
| 161 | - Page.class_eval { alias_method :feeling_good?, :old_feeling_good } | |
| 162 | - end | |
| 163 | - | |
| 164 | - def test_version_if_condition_with_block | |
| 165 | - # set new if condition | |
| 166 | - old_condition = Page.version_condition | |
| 167 | - Page.version_condition = Proc.new { |page| page.title[0..0] == 'b' } | |
| 168 | - | |
| 169 | - p = Page.create! :title => "title" | |
| 170 | - assert_equal 1, p.version # version does not increment | |
| 171 | - assert_equal 1, p.versions.count | |
| 172 | - | |
| 173 | - p.update_attributes(:title => 'a title') | |
| 174 | - assert_equal 1, p.version # version does not increment | |
| 175 | - assert_equal 1, p.versions.count | |
| 176 | - | |
| 177 | - p.update_attributes(:title => 'b title') | |
| 178 | - assert_equal 2, p.version | |
| 179 | - assert_equal 2, p.versions.count | |
| 180 | - | |
| 181 | - # reset original if condition | |
| 182 | - Page.version_condition = old_condition | |
| 183 | - end | |
| 184 | - | |
| 185 | - def test_version_no_limit | |
| 186 | - p = Page.create! :title => "title", :body => 'first body' | |
| 187 | - p.save | |
| 188 | - p.save | |
| 189 | - 5.times do |i| | |
| 190 | - p.title = "title#{i}" | |
| 191 | - p.save | |
| 192 | - assert_equal "title#{i}", p.title | |
| 193 | - assert_equal (i+2), p.version | |
| 194 | - end | |
| 195 | - end | |
| 196 | - | |
| 197 | - def test_version_max_limit | |
| 198 | - p = LockedPage.create! :title => "title" | |
| 199 | - p.update_attributes(:title => "title1") | |
| 200 | - p.update_attributes(:title => "title2") | |
| 201 | - 5.times do |i| | |
| 202 | - p.title = "title#{i}" | |
| 203 | - p.save | |
| 204 | - assert_equal "title#{i}", p.title | |
| 205 | - assert_equal (i+4), p.lock_version | |
| 206 | - assert p.versions(true).size <= 2, "locked version can only store 2 versions" | |
| 207 | - end | |
| 208 | - end | |
| 209 | - | |
| 210 | - def test_track_altered_attributes_default_value | |
| 211 | - assert !Page.track_altered_attributes | |
| 212 | - assert LockedPage.track_altered_attributes | |
| 213 | - assert SpecialLockedPage.track_altered_attributes | |
| 214 | - end | |
| 215 | - | |
| 216 | - def test_track_altered_attributes | |
| 217 | - p = LockedPage.create! :title => "title" | |
| 218 | - assert_equal 1, p.lock_version | |
| 219 | - assert_equal 1, p.versions(true).size | |
| 220 | - | |
| 221 | - p.body = 'whoa' | |
| 222 | - assert !p.save_version? | |
| 223 | - p.save | |
| 224 | - assert_equal 2, p.lock_version # still increments version because of optimistic locking | |
| 225 | - assert_equal 1, p.versions(true).size | |
| 226 | - | |
| 227 | - p.title = 'updated title' | |
| 228 | - assert p.save_version? | |
| 229 | - p.save | |
| 230 | - assert_equal 3, p.lock_version | |
| 231 | - assert_equal 1, p.versions(true).size # version 1 deleted | |
| 232 | - | |
| 233 | - p.title = 'updated title!' | |
| 234 | - assert p.save_version? | |
| 235 | - p.save | |
| 236 | - assert_equal 4, p.lock_version | |
| 237 | - assert_equal 2, p.versions(true).size # version 1 deleted | |
| 238 | - end | |
| 239 | - | |
| 240 | - def test_find_versions | |
| 241 | - assert_equal 1, locked_pages(:welcome).versions.find(:all, :conditions => ['title LIKE ?', '%weblog%']).size | |
| 242 | - end | |
| 243 | - | |
| 244 | - def test_find_version | |
| 245 | - assert_equal page_versions(:welcome_1), pages(:welcome).versions.find_by_version(23) | |
| 246 | - end | |
| 247 | - | |
| 248 | - def test_with_sequence | |
| 249 | - assert_equal 'widgets_seq', Widget.versioned_class.sequence_name | |
| 250 | - 3.times { Widget.create! :name => 'new widget' } | |
| 251 | - assert_equal 3, Widget.count | |
| 252 | - assert_equal 3, Widget.versioned_class.count | |
| 253 | - end | |
| 254 | - | |
| 255 | - def test_has_many_through | |
| 256 | - assert_equal [authors(:caged), authors(:mly)], pages(:welcome).authors | |
| 257 | - end | |
| 258 | - | |
| 259 | - def test_has_many_through_with_custom_association | |
| 260 | - assert_equal [authors(:caged), authors(:mly)], pages(:welcome).revisors | |
| 261 | - end | |
| 262 | - | |
| 263 | - def test_referential_integrity | |
| 264 | - pages(:welcome).destroy | |
| 265 | - assert_equal 0, Page.count | |
| 266 | - assert_equal 0, Page::Version.count | |
| 267 | - end | |
| 268 | - | |
| 269 | - def test_association_options | |
| 270 | - association = Page.reflect_on_association(:versions) | |
| 271 | - options = association.options | |
| 272 | - assert_equal :delete_all, options[:dependent] | |
| 273 | - | |
| 274 | - association = Widget.reflect_on_association(:versions) | |
| 275 | - options = association.options | |
| 276 | - assert_equal :nullify, options[:dependent] | |
| 277 | - assert_equal 'version desc', options[:order] | |
| 278 | - assert_equal 'widget_id', options[:foreign_key] | |
| 279 | - | |
| 280 | - widget = Widget.create! :name => 'new widget' | |
| 281 | - assert_equal 1, Widget.count | |
| 282 | - assert_equal 1, Widget.versioned_class.count | |
| 283 | - widget.destroy | |
| 284 | - assert_equal 0, Widget.count | |
| 285 | - assert_equal 1, Widget.versioned_class.count | |
| 286 | - end | |
| 287 | - | |
| 288 | - def test_versioned_records_should_belong_to_parent | |
| 289 | - page = pages(:welcome) | |
| 290 | - page_version = page.versions.last | |
| 291 | - assert_equal page, page_version.page | |
| 292 | - end | |
| 293 | - | |
| 294 | - def test_unaltered_attributes | |
| 295 | - landmarks(:washington).attributes = landmarks(:washington).attributes.except("id") | |
| 296 | - assert !landmarks(:washington).changed? | |
| 297 | - end | |
| 298 | - | |
| 299 | - def test_unchanged_string_attributes | |
| 300 | - landmarks(:washington).attributes = landmarks(:washington).attributes.except("id").inject({}) { |params, (key, value)| params.update(key => value.to_s) } | |
| 301 | - assert !landmarks(:washington).changed? | |
| 302 | - end | |
| 303 | - | |
| 304 | - def test_should_find_earliest_version | |
| 305 | - assert_equal page_versions(:welcome_1), pages(:welcome).versions.earliest | |
| 306 | - end | |
| 307 | - | |
| 308 | - def test_should_find_latest_version | |
| 309 | - assert_equal page_versions(:welcome_2), pages(:welcome).versions.latest | |
| 310 | - end | |
| 311 | - | |
| 312 | - def test_should_find_previous_version | |
| 313 | - assert_equal page_versions(:welcome_1), page_versions(:welcome_2).previous | |
| 314 | - assert_equal page_versions(:welcome_1), pages(:welcome).versions.before(page_versions(:welcome_2)) | |
| 315 | - end | |
| 316 | - | |
| 317 | - def test_should_find_next_version | |
| 318 | - assert_equal page_versions(:welcome_2), page_versions(:welcome_1).next | |
| 319 | - assert_equal page_versions(:welcome_2), pages(:welcome).versions.after(page_versions(:welcome_1)) | |
| 320 | - end | |
| 321 | - | |
| 322 | - def test_should_find_version_count | |
| 323 | - assert_equal 2, pages(:welcome).versions.size | |
| 324 | - end | |
| 325 | - | |
| 326 | - def test_if_changed_creates_version_if_a_listed_column_is_changed | |
| 327 | - landmarks(:washington).name = "Washington" | |
| 328 | - assert landmarks(:washington).changed? | |
| 329 | - assert landmarks(:washington).altered? | |
| 330 | - end | |
| 331 | - | |
| 332 | - def test_if_changed_creates_version_if_all_listed_columns_are_changed | |
| 333 | - landmarks(:washington).name = "Washington" | |
| 334 | - landmarks(:washington).latitude = 1.0 | |
| 335 | - landmarks(:washington).longitude = 1.0 | |
| 336 | - assert landmarks(:washington).changed? | |
| 337 | - assert landmarks(:washington).altered? | |
| 338 | - end | |
| 339 | - | |
| 340 | - def test_if_changed_does_not_create_new_version_if_unlisted_column_is_changed | |
| 341 | - landmarks(:washington).doesnt_trigger_version = "This should not trigger version" | |
| 342 | - assert landmarks(:washington).changed? | |
| 343 | - assert !landmarks(:washington).altered? | |
| 344 | - end | |
| 345 | - | |
| 346 | - def test_without_locking_temporarily_disables_optimistic_locking | |
| 347 | - enabled1 = false | |
| 348 | - block_called = false | |
| 349 | - | |
| 350 | - ActiveRecord::Base.lock_optimistically = true | |
| 351 | - LockedPage.without_locking do | |
| 352 | - enabled1 = ActiveRecord::Base.lock_optimistically | |
| 353 | - block_called = true | |
| 354 | - end | |
| 355 | - enabled2 = ActiveRecord::Base.lock_optimistically | |
| 356 | - | |
| 357 | - assert block_called | |
| 358 | - assert !enabled1 | |
| 359 | - assert enabled2 | |
| 360 | - end | |
| 361 | - | |
| 362 | - def test_without_locking_reverts_optimistic_locking_settings_if_block_raises_exception | |
| 363 | - assert_raises(RuntimeError) do | |
| 364 | - LockedPage.without_locking do | |
| 365 | - raise RuntimeError, "oh noes" | |
| 366 | - end | |
| 367 | - end | |
| 368 | - assert ActiveRecord::Base.lock_optimistically | |
| 369 | - end | |
| 370 | -end | |
| 371 | 0 | \ No newline at end of file |