Commit 4001b435cc8e42f14a80853eae274b6472b95a21
1 parent
8042c0ea
Exists in
master
and in
22 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 @@ | @@ -0,0 +1 @@ | ||
1 | +rvm --create use 1.9.2@acts_as_versioned |
vendor/plugins/acts_as_versioned/CHANGELOG
@@ -1,82 +0,0 @@ | @@ -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 | \ No newline at end of file | 0 | \ No newline at end of file |
@@ -0,0 +1,101 @@ | @@ -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,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 | \ No newline at end of file | 0 | \ No newline at end of file |
@@ -0,0 +1,120 @@ | @@ -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 | \ No newline at end of file | 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 | \ No newline at end of file | 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 | \ No newline at end of file | 15 | \ No newline at end of file |
vendor/plugins/acts_as_versioned/VERSION.yml
vendor/plugins/acts_as_versioned/acts_as_versioned.gemspec
1 | # -*- encoding: utf-8 -*- | 1 | # -*- encoding: utf-8 -*- |
2 | 2 | ||
3 | Gem::Specification.new do |s| | 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 | s.require_paths = ["lib"] | 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 | if s.respond_to? :specification_version then | 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 | else | 26 | else |
27 | + s.add_dependency(%q<activerecord>, [">= 0"]) | ||
26 | end | 28 | end |
27 | else | 29 | else |
30 | + s.add_dependency(%q<activerecord>, [">= 0"]) | ||
28 | end | 31 | end |
29 | end | 32 | end |
vendor/plugins/acts_as_versioned/lib/acts_as_versioned.rb
@@ -18,6 +18,7 @@ | @@ -18,6 +18,7 @@ | ||
18 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | 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 | 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. | 20 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
21 | +require 'active_support/concern' | ||
21 | 22 | ||
22 | module ActiveRecord #:nodoc: | 23 | module ActiveRecord #:nodoc: |
23 | module Acts #:nodoc: | 24 | module Acts #:nodoc: |
@@ -66,203 +67,206 @@ module ActiveRecord #:nodoc: | @@ -66,203 +67,206 @@ module ActiveRecord #:nodoc: | ||
66 | # | 67 | # |
67 | # See ActiveRecord::Acts::Versioned::ClassMethods#acts_as_versioned for configuration options | 68 | # See ActiveRecord::Acts::Versioned::ClassMethods#acts_as_versioned for configuration options |
68 | module Versioned | 69 | module Versioned |
70 | + VERSION = "0.6.0" | ||
69 | CALLBACKS = [:set_new_version, :save_version, :save_version?] | 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 | end | 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 | end | 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 | end | 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 | end | 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 | end | 270 | end |
267 | 271 | ||
268 | # Saves a version of the model in the versioned table. This is called in the after_save callback by default | 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,7 +296,7 @@ module ActiveRecord #:nodoc: | ||
292 | if version.is_a?(self.class.versioned_class) | 296 | if version.is_a?(self.class.versioned_class) |
293 | return false unless version.send(self.class.versioned_foreign_key) == id and !version.new_record? | 297 | return false unless version.send(self.class.versioned_foreign_key) == id and !version.new_record? |
294 | else | 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 | end | 300 | end |
297 | self.clone_versioned_model(version, self) | 301 | self.clone_versioned_model(version, self) |
298 | send("#{self.class.version_column}=", version.send(self.class.version_column)) | 302 | send("#{self.class.version_column}=", version.send(self.class.version_column)) |
@@ -320,23 +324,33 @@ module ActiveRecord #:nodoc: | @@ -320,23 +324,33 @@ module ActiveRecord #:nodoc: | ||
320 | end | 324 | end |
321 | end | 325 | end |
322 | end | 326 | end |
323 | - | 327 | + |
324 | def altered? | 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 | end | 330 | end |
327 | 331 | ||
328 | # Clones a model. Used when saving a new version or reverting a model's version. | 332 | # Clones a model. Used when saving a new version or reverting a model's version. |
329 | def clone_versioned_model(orig_model, new_model) | 333 | def clone_versioned_model(orig_model, new_model) |
330 | self.class.versioned_columns.each do |col| | 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 | end | 338 | end |
333 | 339 | ||
334 | if orig_model.is_a?(self.class.versioned_class) | 340 | if orig_model.is_a?(self.class.versioned_class) |
335 | new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column] | 341 | new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column] |
336 | elsif new_model.is_a?(self.class.versioned_class) | 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 | end | 346 | end |
339 | end | 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 | # Checks whether a new version shall be saved or not. Calls <tt>version_condition_met?</tt> and <tt>changed?</tt>. | 355 | # Checks whether a new version shall be saved or not. Calls <tt>version_condition_met?</tt> and <tt>changed?</tt>. |
342 | def save_version? | 356 | def save_version? |
@@ -347,12 +361,12 @@ module ActiveRecord #:nodoc: | @@ -347,12 +361,12 @@ module ActiveRecord #:nodoc: | ||
347 | # custom version condition checking. | 361 | # custom version condition checking. |
348 | def version_condition_met? | 362 | def version_condition_met? |
349 | case | 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 | end | 370 | end |
357 | end | 371 | end |
358 | 372 | ||
@@ -376,19 +390,23 @@ module ActiveRecord #:nodoc: | @@ -376,19 +390,23 @@ module ActiveRecord #:nodoc: | ||
376 | self.class.without_locking(&block) | 390 | self.class.without_locking(&block) |
377 | end | 391 | end |
378 | 392 | ||
379 | - def empty_callback() end #:nodoc: | 393 | + def empty_callback() |
394 | + end | ||
395 | + | ||
396 | + #:nodoc: | ||
380 | 397 | ||
381 | protected | 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 | module ClassMethods | 411 | module ClassMethods |
394 | # Returns an array of columns that are versioned. See non_versioned_columns | 412 | # Returns an array of columns that are versioned. See non_versioned_columns |
@@ -410,28 +428,28 @@ module ActiveRecord #:nodoc: | @@ -410,28 +428,28 @@ module ActiveRecord #:nodoc: | ||
410 | end | 428 | end |
411 | 429 | ||
412 | return if connection.table_exists?(versioned_table_name) | 430 | return if connection.table_exists?(versioned_table_name) |
413 | - | 431 | + |
414 | self.connection.create_table(versioned_table_name, create_table_options) do |t| | 432 | self.connection.create_table(versioned_table_name, create_table_options) do |t| |
415 | t.column versioned_foreign_key, :integer | 433 | t.column versioned_foreign_key, :integer |
416 | t.column version_column, :integer | 434 | t.column version_column, :integer |
417 | end | 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 | end | 443 | end |
426 | 444 | ||
427 | if type_col = self.columns_hash[inheritance_column] | 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 | end | 451 | end |
434 | - | 452 | + |
435 | self.connection.add_index versioned_table_name, versioned_foreign_key | 453 | self.connection.add_index versioned_table_name, versioned_foreign_key |
436 | end | 454 | end |
437 | 455 | ||
@@ -447,7 +465,7 @@ module ActiveRecord #:nodoc: | @@ -447,7 +465,7 @@ module ActiveRecord #:nodoc: | ||
447 | # end | 465 | # end |
448 | # | 466 | # |
449 | def without_revision(&block) | 467 | def without_revision(&block) |
450 | - class_eval do | 468 | + class_eval do |
451 | CALLBACKS.each do |attr_name| | 469 | CALLBACKS.each do |attr_name| |
452 | alias_method "orig_#{attr_name}".to_sym, attr_name | 470 | alias_method "orig_#{attr_name}".to_sym, attr_name |
453 | alias_method attr_name, :empty_callback | 471 | alias_method attr_name, :empty_callback |
@@ -455,7 +473,7 @@ module ActiveRecord #:nodoc: | @@ -455,7 +473,7 @@ module ActiveRecord #:nodoc: | ||
455 | end | 473 | end |
456 | block.call | 474 | block.call |
457 | ensure | 475 | ensure |
458 | - class_eval do | 476 | + class_eval do |
459 | CALLBACKS.each do |attr_name| | 477 | CALLBACKS.each do |attr_name| |
460 | alias_method attr_name, "orig_#{attr_name}".to_sym | 478 | alias_method attr_name, "orig_#{attr_name}".to_sym |
461 | end | 479 | end |
@@ -483,4 +501,4 @@ module ActiveRecord #:nodoc: | @@ -483,4 +501,4 @@ module ActiveRecord #:nodoc: | ||
483 | end | 501 | end |
484 | end | 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,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 | \ No newline at end of file | 0 | \ No newline at end of file |
vendor/plugins/acts_as_versioned/test/database.yml
@@ -1,18 +0,0 @@ | @@ -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 | \ No newline at end of file | 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,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,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 | \ No newline at end of file | 0 | \ No newline at end of file |
vendor/plugins/acts_as_versioned/test/fixtures/page.rb
@@ -1,43 +0,0 @@ | @@ -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 | \ No newline at end of file | 0 | \ No newline at end of file |
vendor/plugins/acts_as_versioned/test/fixtures/page_versions.yml
@@ -1,16 +0,0 @@ | @@ -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
@@ -1,6 +0,0 @@ | @@ -1,6 +0,0 @@ | ||
1 | -class Widget < ActiveRecord::Base | ||
2 | - acts_as_versioned :sequence_name => 'widgets_seq', :association_options => { | ||
3 | - :dependent => :nullify, :order => 'version desc' | ||
4 | - } | ||
5 | - non_versioned_columns << 'foo' | ||
6 | -end | ||
7 | \ No newline at end of file | 0 | \ No newline at end of file |
vendor/plugins/acts_as_versioned/test/migration_test.rb
@@ -1,46 +0,0 @@ | @@ -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,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,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 | \ No newline at end of file | 0 | \ No newline at end of file |