kb-acts_as_revisable 1.0.4 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,9 +20,9 @@ module WithoutScope
20
20
 
21
21
  base.instance_eval do
22
22
  define_callbacks :before_branch, :after_branch
23
- has_many :branches, (revisable_options.revision_association_options || {}).merge({:class_name => base.class_name, :foreign_key => :revisable_branched_from_id})
23
+ has_many :branches, (revisable_options.revision_association_options || {}).merge({:class_name => base.name, :foreign_key => :revisable_branched_from_id})
24
24
 
25
- belongs_to :branch_source, :class_name => base.class_name, :foreign_key => :revisable_branched_from_id
25
+ belongs_to :branch_source, :class_name => base.name, :foreign_key => :revisable_branched_from_id
26
26
  after_save :execute_blocks_after_save
27
27
  end
28
28
  end
@@ -8,8 +8,7 @@ module WithoutScope
8
8
  end
9
9
 
10
10
  def destroy
11
- now = Time.zone.now
12
-
11
+ now = Time.current
13
12
  prev = self.revisions.first
14
13
  self.revisable_deleted_at = now
15
14
  self.revisable_is_current = false
@@ -40,11 +40,11 @@ module WithoutScope
40
40
  has_many assoc, (revisable_options.revision_association_options || {}).merge({:class_name => revision_class_name, :foreign_key => :revisable_original_id, :order => "#{quoted_table_name}.#{connection.quote_column_name(:revisable_number)} DESC", :dependent => :destroy})
41
41
  end
42
42
  end
43
-
43
+
44
44
  if !Object.const_defined?(base.revision_class_name) && base.revisable_options.generate_revision_class?
45
- Object.const_set(base.revision_class_name, Class.new(ActiveRecord::Base)).class_eval do
45
+ Object.const_set(base.revision_class_name, Class.new(ActiveRecord::Base)).instance_eval do
46
46
  acts_as_revision
47
- end
47
+ end
48
48
  end
49
49
  end
50
50
 
@@ -77,7 +77,7 @@ module WithoutScope
77
77
  by
78
78
  when :first
79
79
  revisions.last
80
- when :previous
80
+ when :previous, :last
81
81
  revisions.first
82
82
  when Time
83
83
  revisions.find(:first, :conditions => ["? >= ? and ? <= ?", :revisable_revised_at, by, :revisable_current_at, by])
@@ -329,7 +329,13 @@ module WithoutScope
329
329
  self.revisable_revision = nil
330
330
  return true
331
331
  elsif self.revisable_revision
332
- self.revisable_revision.save
332
+ if self.class.revision_class.respond_to?(:without_stamps)
333
+ self.class.revision_class.without_stamps do
334
+ self.revisable_revision.save
335
+ end
336
+ else
337
+ self.revisable_revision.save
338
+ end
333
339
  revisions.reload
334
340
  run_callbacks(:after_revise)
335
341
  end
@@ -446,7 +452,7 @@ module WithoutScope
446
452
  # Returns the +revision_class_name+ as configured in
447
453
  # +acts_as_revisable+.
448
454
  def revision_class_name #:nodoc:
449
- self.revisable_options.revision_class_name || "#{self.class_name}Revision"
455
+ self.revisable_options.revision_class_name || "#{self.name}Revision"
450
456
  end
451
457
 
452
458
  # Returns the actual +Revision+ class based on the
@@ -29,15 +29,7 @@ module WithoutScope
29
29
  [:current_revision, revisable_association_name.to_sym].each do |a|
30
30
  belongs_to a, :class_name => revisable_class_name, :foreign_key => :revisable_original_id
31
31
  end
32
-
33
- # add an author association if there is such a class
34
- begin
35
- if User.is_a?(Class) && User.respond_to?('current_user')
36
- belongs_to :author, :class_name => 'User', :foreign_key => 'revisable_author_id'
37
- end
38
- rescue NameError
39
- end
40
-
32
+
41
33
  [[:ancestors, "<"], [:descendants, ">"]].each do |a|
42
34
  # Jumping through hoops here to try and make sure the
43
35
  # :finder_sql is cross-database compatible. :finder_sql
@@ -73,15 +65,13 @@ module WithoutScope
73
65
 
74
66
  # Sets some initial values for a new revision.
75
67
  def revision_setup #:nodoc:
76
- now = Time.zone.now
68
+ now = Time.current
77
69
  prev = current_revision.revisions.first
78
70
  prev.update_attribute(:revisable_revised_at, now) if prev
79
71
  self[:revisable_current_at] = now + 1.second
80
72
  self[:revisable_is_current] = false
81
- self[:revisable_author_id] = (User.current_user.id rescue nil)
82
73
  self[:revisable_branched_from_id] = current_revision[:revisable_branched_from_id]
83
- self[:revisable_type] = current_revision[:type]
84
- self[:revisable_number] = (self.class.maximum(:revisable_number, :conditions => {:revisable_original_id => self[:revisable_original_id]}) || 0) + 1
74
+ self[:revisable_type] = current_revision[:type] || current_revision.class.name
85
75
  end
86
76
 
87
77
  def grab_my_branches
@@ -112,7 +102,7 @@ module WithoutScope
112
102
  # Returns the +revisable_class_name+ as configured in
113
103
  # +acts_as_revisable+.
114
104
  def revisable_class_name #:nodoc:
115
- self.revisable_options.revisable_class_name || self.class_name.gsub(/Revision/, '')
105
+ self.revisable_options.revisable_class_name || self.name.gsub(/Revision/, '')
116
106
  end
117
107
 
118
108
  # Returns the actual +Revisable+ class based on the
@@ -1,5 +1,6 @@
1
1
  require 'acts_as_revisable/options'
2
2
  require 'acts_as_revisable/quoted_columns'
3
+ require 'acts_as_revisable/validations'
3
4
  require 'acts_as_revisable/acts/common'
4
5
  require 'acts_as_revisable/acts/revision'
5
6
  require 'acts_as_revisable/acts/revisable'
@@ -45,6 +46,7 @@ module WithoutScope
45
46
  self.revisable_options = Options.new(options, &block)
46
47
 
47
48
  self.send(:include, Common)
49
+ self.send(:extend, Validations) unless self.revisable_options.no_validation_scoping?
48
50
  self.send(:include, WithoutScope::QuotedColumnConditions)
49
51
  end
50
52
  end
@@ -0,0 +1,11 @@
1
+ module WithoutScope
2
+ module ActsAsRevisable
3
+ module Validations
4
+ def validates_uniqueness_of(*args)
5
+ options = args.extract_options!
6
+ (options[:scope] ||= []) << :revisable_is_current
7
+ super(*(args << options))
8
+ end
9
+ end
10
+ end
11
+ end
@@ -2,8 +2,8 @@ module WithoutScope #:nodoc:
2
2
  module ActsAsRevisable
3
3
  module VERSION #:nodoc:
4
4
  MAJOR = 1
5
- MINOR = 0
6
- TINY = 3
5
+ MINOR = 1
6
+ TINY = 1
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY].join('.')
9
9
  end
data/spec/find_spec.rb CHANGED
@@ -26,5 +26,9 @@ describe WithoutScope::ActsAsRevisable do
26
26
  it "should find revisions with conditions" do
27
27
  Project.find(:all, :conditions => {:name => "Rich"}, :with_revisions => true).should == [@project1.find_revision(:previous)]
28
28
  end
29
+
30
+ it "should find last revision" do
31
+ @project1.find_revision(:last).should == @project1.find_revision(:previous)
32
+ end
29
33
  end
30
34
  end
data/spec/general_spec.rb CHANGED
@@ -7,6 +7,22 @@ describe WithoutScope::ActsAsRevisable do
7
7
 
8
8
  before(:each) do
9
9
  @project = Project.create(:name => "Rich", :notes => "this plugin's author")
10
+ @post = Post.create(:name => 'a name')
11
+ end
12
+
13
+ describe "with auto-detected revision class" do
14
+ it "should find the revision class" do
15
+ Post.revision_class.should == PostRevision
16
+ end
17
+
18
+ it "should find the revisable class" do
19
+ PostRevision.revisable_class.should == Post
20
+ end
21
+
22
+ it "should use the revision class" do
23
+ @post.update_attribute(:name, 'another name')
24
+ @post.revisions(true).first.class.should == PostRevision
25
+ end
10
26
  end
11
27
 
12
28
  describe "with auto-generated revision class" do
@@ -54,6 +70,10 @@ describe WithoutScope::ActsAsRevisable do
54
70
  @project.sessions.size.should == 1
55
71
  end
56
72
 
73
+ it "should have a single revision with a revision_number of zero" do
74
+ @project.revisions.collect{ |rev| rev.revision_number }.should == [0]
75
+ end
76
+
57
77
  it "should return an instance of the revision class" do
58
78
  @project.revisions.first.should be_an_instance_of(Session)
59
79
  end
@@ -63,6 +83,22 @@ describe WithoutScope::ActsAsRevisable do
63
83
  end
64
84
  end
65
85
 
86
+ describe "with multiple revisions" do
87
+ before(:each) do
88
+ @project.update_attribute(:name, "Stephen")
89
+ @project.update_attribute(:name, "Michael")
90
+ end
91
+
92
+ it "should have a revision_number of two" do
93
+ @project.revision_number.should == 2
94
+ end
95
+
96
+ it "should have revisions with revision_number values of zero and one" do
97
+ @project.revisions.collect{ |rev| rev.revision_number }.should == [1,0]
98
+ end
99
+ end
100
+
101
+
66
102
  describe "with excluded columns modified" do
67
103
  before(:each) do
68
104
  @project.update_attribute(:unimportant, "a new value")
data/spec/spec_helper.rb CHANGED
@@ -15,7 +15,7 @@ end
15
15
  $:.unshift(File.dirname(__FILE__) + '/../lib')
16
16
  require 'acts_as_revisable'
17
17
 
18
- ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
18
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
19
19
 
20
20
  def setup_db
21
21
  ActiveRecord::Schema.define(:version => 1) do
@@ -45,6 +45,14 @@ def setup_db
45
45
  t.datetime :revisable_current_at, :revisable_revised_at, :revisable_deleted_at
46
46
  t.timestamps
47
47
  end
48
+
49
+ create_table :posts do |t|
50
+ t.string :name, :revisable_name, :revisable_type, :type
51
+ t.boolean :revisable_is_current
52
+ t.integer :revisable_original_id, :revisable_branched_from_id, :revisable_number
53
+ t.datetime :revisable_current_at, :revisable_revised_at, :revisable_deleted_at
54
+ t.timestamps
55
+ end
48
56
  end
49
57
  end
50
58
 
@@ -89,5 +97,25 @@ class Session < ActiveRecord::Base
89
97
  end
90
98
 
91
99
  class Foo < ActiveRecord::Base
92
- acts_as_revisable :generate_revision_class => true
100
+ acts_as_revisable :generate_revision_class => true, :no_validation_scoping => true
101
+
102
+ validates_uniqueness_of :name
103
+ end
104
+
105
+ class Post < ActiveRecord::Base
106
+ acts_as_revisable
107
+
108
+ validates_uniqueness_of :name
109
+ end
110
+
111
+ class PostRevision < ActiveRecord::Base
112
+ acts_as_revision
113
+ end
114
+
115
+ class Article < Post
116
+ acts_as_revisable
117
+ end
118
+
119
+ class ArticleRevision < PostRevision
120
+ acts_as_revision
93
121
  end
data/spec/sti_spec.rb ADDED
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe WithoutScope::ActsAsRevisable, "with single table inheritance" do
4
+ after(:each) do
5
+ cleanup_db
6
+ end
7
+
8
+ before(:each) do
9
+ @article = Article.create(:name => 'an article')
10
+ @post = Post.create(:name => 'a post')
11
+ end
12
+
13
+ describe "after a revision" do
14
+ it "an article has revisions of the right type" do
15
+ @article.revise!
16
+ @article.revisions(true).first.class.should == ArticleRevision
17
+ end
18
+
19
+ it "a post has revisions of the right type" do
20
+ @post.revise!
21
+ @post.revisions(true).first.class.should == PostRevision
22
+ end
23
+
24
+ it "revisable_type column is nil for the root type" do
25
+ @post.revise!
26
+ @post.revisions(true).first.revisable_type.should == 'Post'
27
+ end
28
+
29
+ it "revisable_type column is set properly" do
30
+ @article.revise!
31
+ @article.revisions(true).first.revisable_type.should == 'Article'
32
+ end
33
+
34
+ it "can find an article by name" do
35
+ Article.find_by_name('an article').should_not be_nil
36
+ end
37
+
38
+ it "can find a post by name" do
39
+ Post.find_by_name('a post').should_not be_nil
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,25 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe WithoutScope::ActsAsRevisable, "with validations" do
4
+ after(:each) do
5
+ cleanup_db
6
+ end
7
+
8
+ before(:each) do
9
+ @post = Post.create(:name => 'a post')
10
+ @foo = Foo.create(:name => 'a foo')
11
+
12
+ end
13
+
14
+ describe "unique fields" do
15
+ it "should allow revisions" do
16
+ lambda {@post.revise!; @post.revise!}.should_not raise_error
17
+ end
18
+ end
19
+
20
+ describe "unique fields with validation scoping off" do
21
+ it "should not allow revisions" do
22
+ lambda {@foo.revise!; @foo.revise!}.should raise_error
23
+ end
24
+ end
25
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kb-acts_as_revisable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rich Cavanaugh
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-05-16 00:00:00 -07:00
13
+ date: 2009-10-06 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -37,8 +37,8 @@ files:
37
37
  - spec/revert_spec.rb
38
38
  - spec/spec.opts
39
39
  - spec/spec_helper.rb
40
- - lib/acts_as_revisable
41
- - lib/acts_as_revisable/acts
40
+ - spec/sti_spec.rb
41
+ - spec/validations_spec.rb
42
42
  - lib/acts_as_revisable/acts/common.rb
43
43
  - lib/acts_as_revisable/acts/deletable.rb
44
44
  - lib/acts_as_revisable/acts/revisable.rb
@@ -47,16 +47,16 @@ files:
47
47
  - lib/acts_as_revisable/gem_spec_options.rb
48
48
  - lib/acts_as_revisable/options.rb
49
49
  - lib/acts_as_revisable/quoted_columns.rb
50
+ - lib/acts_as_revisable/validations.rb
50
51
  - lib/acts_as_revisable/version.rb
51
52
  - lib/acts_as_revisable.rb
52
- - generators/revisable_migration
53
53
  - generators/revisable_migration/revisable_migration_generator.rb
54
- - generators/revisable_migration/templates
55
54
  - generators/revisable_migration/templates/migration.rb
56
55
  - rails/init.rb
57
56
  has_rdoc: true
58
57
  homepage: http://github.com/rich/acts_as_revisable
59
- licenses:
58
+ licenses: []
59
+
60
60
  post_install_message:
61
61
  rdoc_options:
62
62
  - --main
@@ -80,7 +80,7 @@ requirements: []
80
80
  rubyforge_project:
81
81
  rubygems_version: 1.3.5
82
82
  signing_key:
83
- specification_version: 2
83
+ specification_version: 3
84
84
  summary: acts_as_revisable enables revision tracking, querying, reverting and branching of ActiveRecord models. Inspired by acts_as_versioned.
85
85
  test_files: []
86
86