railsgarden-has_draft 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG ADDED
@@ -0,0 +1 @@
1
+ * [0.1.0] Initial Version
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest ADDED
@@ -0,0 +1,18 @@
1
+ CHANGELOG
2
+ has_draft_plugin.sqlite3
3
+ init.rb
4
+ install.rb
5
+ lib/has_draft.rb
6
+ Manifest
7
+ MIT-LICENSE
8
+ Rakefile
9
+ README.rdoc
10
+ tasks/has_draft_tasks.rake
11
+ test/config/database.yml
12
+ test/fixtures/article_drafts.yml
13
+ test/fixtures/articles.yml
14
+ test/has_draft_test.rb
15
+ test/models/article.rb
16
+ test/schema.rb
17
+ test/test_helper.rb
18
+ uninstall.rb
data/README.rdoc ADDED
@@ -0,0 +1,158 @@
1
+ == Has Draft
2
+
3
+ Allows for multiple "drafts" of a model which can be useful when developing:
4
+ * Draft/Live Version of Pages, for examples
5
+ * A workflow system whereby a live copy may need to be active while a draft copy is
6
+ awaiting approval.
7
+
8
+ The semantics of this as well as most of the inspiration comes from version_fu,
9
+ an excellent plugin for a similar purpose of maintaining several "versions" of a model.
10
+
11
+ This was built to be able to be tacked on to existing models, so the data schema doesn't need to change
12
+ at all for the model this is applied to. As such, drafts are actually stored in a nearly-identical table
13
+ and there is a has_one relationship to this. This separation allows the base model to really be treated
14
+ just as before without having to apply conditions in queries to make sure you are really getting the
15
+ "live" (non-draft) copy: Page.all will still only return the non-draft pages. This separate table is backed by
16
+ a model created on the fly as a constant on the original model class. For example if a Page has_draft,
17
+ a Page::Draft class will exist as the model for the page_drafts table.
18
+
19
+ == Installation
20
+
21
+ # In environment.rb
22
+ config.gem 'railsgarden-has_draft', :lib => 'has_draft', :source => 'http://gems.github.com'
23
+
24
+ == Basic Example
25
+
26
+ ## First Migration (If Creating base model and drafts at the same time):
27
+ class InitialSchema < ActiveRecord::Migration
28
+
29
+ [:articles, :article_drafts].each do |table_name|
30
+ create_table table_name, :force => true do |t|
31
+ t.references :article if table_name == :article_drafts
32
+
33
+ t.string :title
34
+ t.text :summary
35
+ t.text :body
36
+ t.date :post_date
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+
43
+ ## Model Class
44
+ class Article < ActiveRecord::Base
45
+ has_draft
46
+ end
47
+
48
+ ## Exposed Class Methods & Scopes:
49
+ Article.draft_class
50
+ => Article::Draft
51
+ Article.with_draft.all
52
+ => (Articles that have an associated draft)
53
+ Article.without_draft.all
54
+ => (Articles with no associated draft)
55
+
56
+
57
+
58
+ ## Usage Examples:
59
+
60
+ article = Article.create(
61
+ :title => "My Title",
62
+ :summary => "Information here.",
63
+ :body => "Full body",
64
+ :post_date => Date.today
65
+ )
66
+
67
+ article.has_draft?
68
+ => false
69
+
70
+ article.instantiate_draft!
71
+
72
+ article.has_draft?
73
+ => true
74
+
75
+ article.draft
76
+ => Article::Draft Instance
77
+
78
+ article.draft.update_attributes(
79
+ :title => "New Title"
80
+ )
81
+
82
+ article.replace_with_draft!
83
+
84
+ article.title
85
+ => "New Title"
86
+
87
+ article.destroy_draft!
88
+
89
+ article.has_draft?
90
+ => false
91
+
92
+ == Custom Options
93
+
94
+ ## First Migration (If Creating base model and drafts at the same time):
95
+ class InitialSchema < ActiveRecord::Migration
96
+
97
+ [:articles, :article_copies].each do |table_name|
98
+ create_table table_name, :force => true do |t|
99
+ t.integer :news_article_id if table_name == :article_copies
100
+
101
+ t.string :title
102
+ t.text :summary
103
+ t.text :body
104
+ t.date :post_date
105
+ end
106
+ end
107
+
108
+ end
109
+
110
+ ## Model Class
111
+ class Article < ActiveRecord::Base
112
+ has_draft :class_name => 'Copy', :foreign_key => :news_article_id, :table_name => 'article_copies'
113
+ end
114
+
115
+ == Method Callbacks
116
+
117
+ There are three callbacks you can specify directly as methods:
118
+
119
+ class Article < ActiveRecord::Base
120
+ has_draft
121
+
122
+ def before_instantiate_draft
123
+ # Do Something
124
+ end
125
+
126
+ def before_replace_with_draft
127
+ # Do Something
128
+ end
129
+
130
+ def before_destroy_draft
131
+ # Do Something
132
+ end
133
+ end
134
+
135
+
136
+
137
+ == Extending the Draft Class
138
+
139
+ Because you don't directly define the draft class, you can specify a block of code to be run in its
140
+ context by passing a block to has_draft:
141
+
142
+ class Article < ActiveRecord::Base
143
+ belongs_to :user
144
+
145
+ has_draft do
146
+ belongs_to :last_updated_user
147
+
148
+ def approve!
149
+ self.approved_at = Time.now
150
+ self.save
151
+ end
152
+ end
153
+
154
+ end
155
+
156
+
157
+
158
+ Copyright (c) 2008 Ben Hughes, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ require 'rubygems'
2
+ require 'echoe'
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+
7
+ desc 'Default: run unit tests.'
8
+ task :default => :test
9
+
10
+ desc 'Test the has_draft plugin.'
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << 'lib'
13
+ t.pattern = 'test/**/*_test.rb'
14
+ t.verbose = true
15
+ end
16
+
17
+ desc 'Generate documentation for the has_draft plugin.'
18
+ Rake::RDocTask.new(:rdoc) do |rdoc|
19
+ rdoc.rdoc_dir = 'rdoc'
20
+ rdoc.title = 'HasDraft'
21
+ rdoc.options << '--line-numbers' << '--inline-source'
22
+ rdoc.rdoc_files.include('README')
23
+ rdoc.rdoc_files.include('lib/**/*.rb')
24
+ end
25
+
26
+
27
+ Echoe.new('has_draft', '0.1.0') do |p|
28
+ p.description = "Allows for your ActiveRecord models to have drafts which are stored in a separate duplicate table."
29
+ p.url = "http://github.com/railsgarden/has_draft"
30
+ p.author = "Ben Hughes"
31
+ p.email = "ben@railsgarden.com"
32
+ p.ignore_pattern = ["tmp/*", "script/*"]
33
+ p.development_dependencies = []
34
+ end
35
+
36
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
37
+
data/has_draft.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{has_draft}
5
+ s.version = "0.1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Ben Hughes"]
9
+ s.date = %q{2009-01-16}
10
+ s.description = %q{Allows for your ActiveRecord models to have drafts which are stored in a separate duplicate table.}
11
+ s.email = %q{ben@railsgarden.com}
12
+ s.extra_rdoc_files = ["CHANGELOG", "lib/has_draft.rb", "README.rdoc", "tasks/has_draft_tasks.rake"]
13
+ s.files = ["CHANGELOG", "has_draft_plugin.sqlite3", "init.rb", "install.rb", "lib/has_draft.rb", "Manifest", "MIT-LICENSE", "Rakefile", "README.rdoc", "tasks/has_draft_tasks.rake", "test/config/database.yml", "test/fixtures/article_drafts.yml", "test/fixtures/articles.yml", "test/has_draft_test.rb", "test/models/article.rb", "test/schema.rb", "test/test_helper.rb", "uninstall.rb", "has_draft.gemspec"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://github.com/railsgarden/has_draft}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Has_draft", "--main", "README.rdoc"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{has_draft}
19
+ s.rubygems_version = %q{1.3.1}
20
+ s.summary = %q{Allows for your ActiveRecord models to have drafts which are stored in a separate duplicate table.}
21
+ s.test_files = ["test/has_draft_test.rb", "test/test_helper.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 2
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ else
29
+ end
30
+ else
31
+ end
32
+ end
data/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'has_draft'
2
+
3
+ ActiveRecord::Base.send(:include, Rubiety::HasDraft)
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
data/lib/has_draft.rb ADDED
@@ -0,0 +1,120 @@
1
+ module Rubiety
2
+ module HasDraft
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def has_draft(options = {}, &block)
9
+ return if self.included_modules.include?(HasDraft::InstanceMethods)
10
+ include HasDraft::InstanceMethods
11
+
12
+ cattr_accessor :draft_class_name, :draft_foreign_key, :draft_table_name, :draft_columns
13
+
14
+ self.draft_class_name = options[:class_name] || 'Draft'
15
+ self.draft_foreign_key = options[:foreign_key] || self.to_s.foreign_key
16
+ self.draft_table_name = options[:table_name] || "#{table_name_prefix}#{base_class.name.demodulize.underscore}_drafts#{table_name_suffix}"
17
+
18
+ # Create Relationship to Draft Copy
19
+ class_eval do
20
+ has_one :draft, :class_name => "#{self.to_s}::#{draft_class_name}",
21
+ :foreign_key => draft_foreign_key,
22
+ :dependent => :destroy
23
+
24
+ named_scope :with_draft, :include => [:draft], :conditions => "#{draft_table_name}.id IS NOT NULL"
25
+ named_scope :without_draft, :include => [:draft], :conditions => "#{draft_table_name}.id IS NULL"
26
+ end
27
+
28
+ # Dynamically Create Model::Draft Class
29
+ const_set(draft_class_name, Class.new(ActiveRecord::Base))
30
+
31
+ draft_class.cattr_accessor :original_class
32
+ draft_class.original_class = self
33
+ draft_class.set_table_name(draft_table_name)
34
+
35
+ # Draft Parent Association
36
+ draft_class.belongs_to self.to_s.demodulize.underscore.to_sym, :class_name => "::#{self.to_s}", :foreign_key => draft_foreign_key
37
+
38
+ # Block extension
39
+ draft_class.class_eval(&block) if block_given?
40
+
41
+ # Finally setup which columns to draft
42
+ self.draft_columns = draft_class.new.attributes.keys - [draft_class.primary_key, draft_foreign_key, 'created_at', 'updated_at', inheritance_column]
43
+ end
44
+
45
+ def draft_class
46
+ const_get(draft_class_name)
47
+ end
48
+ end
49
+
50
+ module InstanceMethods
51
+ def has_draft?
52
+ !self.draft.nil?
53
+ end
54
+
55
+ def save_to_draft(perform_validation = true)
56
+ return false if perform_validation and !self.valid?
57
+
58
+ instantiate_draft! unless has_draft?
59
+ copy_attributes_to_draft
60
+
61
+ self.draft.save(perform_validation)
62
+ self.reload
63
+ end
64
+
65
+ def instantiate_draft
66
+ self.draft = self.build_draft
67
+
68
+ copy_attributes_to_draft
69
+ before_instantiate_draft
70
+
71
+ self.draft
72
+ end
73
+
74
+ def instantiate_draft!
75
+ returning instantiate_draft do |draft|
76
+ draft.save unless self.new_record?
77
+ end
78
+ end
79
+
80
+ def copy_attributes_to_draft
81
+ self.class.draft_columns.each do |attribute|
82
+ self.draft.send("#{attribute}=", send(attribute))
83
+ end
84
+ self
85
+ end
86
+
87
+ def copy_attributes_from_draft
88
+ self.class.draft_columns.each do |attribute|
89
+ self.send("#{attribute}=", self.draft.send(attribute))
90
+ end
91
+ self
92
+ end
93
+
94
+ def before_instantiate_draft
95
+ end
96
+
97
+ def replace_with_draft!
98
+ copy_attributes_from_draft
99
+
100
+ before_replace_with_draft
101
+
102
+ self.save unless self.new_record?
103
+ self
104
+ end
105
+
106
+ def before_replace_with_draft
107
+ end
108
+
109
+ def destroy_draft!
110
+ before_destroy_draft
111
+
112
+ self.draft.destroy if self.draft
113
+ self.draft(true)
114
+ end
115
+
116
+ def before_destroy_draft
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :has_draft do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,18 @@
1
+ sqlite:
2
+ :adapter: sqlite
3
+ :dbfile: has_draft_plugin.sqlite
4
+ sqlite3:
5
+ :adapter: sqlite3
6
+ :dbfile: has_draft_plugin.sqlite3
7
+ postgresql:
8
+ :adapter: postgresql
9
+ :username: postgres
10
+ :password: postgres
11
+ :database: has_draft_plugin_test
12
+ :min_messages: ERROR
13
+ mysql:
14
+ :adapter: mysql
15
+ :host: localhost
16
+ :username: root
17
+ :password:
18
+ :database: has_draft_plugin_test
@@ -0,0 +1,12 @@
1
+ article_with_draft:
2
+ article_id: <%= Fixtures.identify('article_with_draft') %>
3
+ title: Article With Draft Changed
4
+ summary: >
5
+ Changed: Sed cursus cursus velit. Sed cursus cursus velit.
6
+ body: >
7
+ Changed: Nunc auctor bibendum eros. Maecenas porta accumsan mauris. Etiam enim enim, elementum sed, bibendum quis, rhoncus non,
8
+ metus. Fusce neque dolor, adipiscing sed, consectetuer et, lacinia sit amet, quam. Suspendisse wisi quam,
9
+ consectetuer in, blandit sed, suscipit eu, eros. Etiam ligula enim, tempor ut, blandit nec, mollis eu, lectus.
10
+ Nam cursus. Vivamus iaculis. Aenean risus purus, pharetra in, blandit quis, gravida a, turpis. Donec nisl.
11
+ Aenean eget mi. Fusce mattis est id diam. Phasellus faucibus interdum sapien. Duis quis nunc. Sed enim.
12
+ post_date: <%= Date.today.to_s(:db) %>
@@ -0,0 +1,23 @@
1
+ article_without_draft:
2
+ title: Article Without Draft
3
+ summary: >
4
+ Sed cursus cursus velit. Sed cursus cursus velit.
5
+ body: >
6
+ Nunc auctor bibendum eros. Maecenas porta accumsan mauris. Etiam enim enim, elementum sed, bibendum quis, rhoncus non,
7
+ metus. Fusce neque dolor, adipiscing sed, consectetuer et, lacinia sit amet, quam. Suspendisse wisi quam,
8
+ consectetuer in, blandit sed, suscipit eu, eros. Etiam ligula enim, tempor ut, blandit nec, mollis eu, lectus.
9
+ Nam cursus. Vivamus iaculis. Aenean risus purus, pharetra in, blandit quis, gravida a, turpis. Donec nisl.
10
+ Aenean eget mi. Fusce mattis est id diam. Phasellus faucibus interdum sapien. Duis quis nunc. Sed enim.
11
+ post_date: <%= Date.today.to_s(:db) %>
12
+
13
+ article_with_draft:
14
+ title: Article With Draft
15
+ summary: >
16
+ Sed cursus cursus velit. Sed cursus cursus velit.
17
+ body: >
18
+ Nunc auctor bibendum eros. Maecenas porta accumsan mauris. Etiam enim enim, elementum sed, bibendum quis, rhoncus non,
19
+ metus. Fusce neque dolor, adipiscing sed, consectetuer et, lacinia sit amet, quam. Suspendisse wisi quam,
20
+ consectetuer in, blandit sed, suscipit eu, eros. Etiam ligula enim, tempor ut, blandit nec, mollis eu, lectus.
21
+ Nam cursus. Vivamus iaculis. Aenean risus purus, pharetra in, blandit quis, gravida a, turpis. Donec nisl.
22
+ Aenean eget mi. Fusce mattis est id diam. Phasellus faucibus interdum sapien. Duis quis nunc. Sed enim.
23
+ post_date: <%= Date.today.to_s(:db) %>
@@ -0,0 +1,96 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+ require File.join(File.dirname(__FILE__), 'models/article')
3
+
4
+ class ArticleTest < Test::Unit::TestCase
5
+ fixtures :articles, :article_drafts
6
+ set_fixture_class :article_drafts => Article::Draft
7
+
8
+ context "Article model" do
9
+ should_have_one :draft
10
+ should_have_named_scope :with_draft
11
+ should_have_named_scope :without_draft
12
+
13
+ should_have_class_methods :draft_class_name, :draft_foreign_key, :draft_table_name
14
+
15
+ should "default class name to Draft" do
16
+ assert_equal "Draft", Article.draft_class_name
17
+ end
18
+
19
+ should "expose draft class constant" do
20
+ assert_equal Article::Draft, Article.draft_class
21
+ end
22
+
23
+ should "default foreign key to article_id" do
24
+ assert_equal "article_id", Article.draft_foreign_key
25
+ end
26
+
27
+ should "default table name to article_drafts" do
28
+ assert_equal "article_drafts", Article.draft_table_name
29
+ end
30
+
31
+ context "Draft model" do
32
+ should "have a be defined under Article" do
33
+ assert Article.constants.include?('Draft')
34
+ end
35
+
36
+ should "load" do
37
+ assert_nothing_raised do
38
+ Article::Draft
39
+ end
40
+ end
41
+
42
+ should "expose original class name of Article" do
43
+ assert_equal Article, Article::Draft.original_class
44
+ end
45
+ end
46
+ end
47
+
48
+ context "an article" do
49
+ setup { @article = articles(:article_without_draft) }
50
+
51
+ context "when instantiating a new draft" do
52
+ setup { @article.instantiate_draft! }
53
+
54
+ should "create draft" do
55
+ assert_not_nil @article.draft
56
+ assert !@article.draft.new_record?
57
+ end
58
+
59
+ should "copy draft fields" do
60
+ Article.draft_columns.each do |column|
61
+ assert_equal @article.send(column), @article.draft.send(column)
62
+ end
63
+ end
64
+ end
65
+
66
+ context "when destroying an existing draft" do
67
+ setup do
68
+ @article = articles(:article_with_draft)
69
+ @article.destroy_draft!
70
+ end
71
+
72
+ should "destroy associated draft" do
73
+ assert_nil @article.draft
74
+ end
75
+ end
76
+
77
+ context "when replacing with draft" do
78
+ setup do
79
+ @article = articles(:article_with_draft)
80
+ @article.replace_with_draft!
81
+ end
82
+
83
+ should "still have draft" do
84
+ assert_not_nil @article.draft
85
+ end
86
+
87
+ should "now have the same field values as draft" do
88
+ Article.draft_columns.each do |column|
89
+ assert_equal @article.send(column), @article.draft.send(column)
90
+ end
91
+ end
92
+ end
93
+
94
+ end
95
+
96
+ end
@@ -0,0 +1,3 @@
1
+ class Article < ActiveRecord::Base
2
+ has_draft
3
+ end
data/test/schema.rb ADDED
@@ -0,0 +1,14 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+
3
+ [:articles, :article_drafts].each do |table_name|
4
+ create_table table_name, :force => true do |t|
5
+ t.references :article if table_name == :article_drafts
6
+
7
+ t.string :title
8
+ t.text :summary
9
+ t.text :body
10
+ t.date :post_date
11
+ end
12
+ end
13
+
14
+ end
@@ -0,0 +1,24 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'active_record'
4
+ require 'active_record/fixtures'
5
+ require 'shoulda/rails'
6
+ require File.expand_path(File.join(File.dirname(__FILE__), '../lib/has_draft'))
7
+
8
+ config = YAML::load(IO.read(File.join(File.dirname(__FILE__), 'config', '/database.yml')))
9
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
10
+ ActiveRecord::Base.configurations = {'test' => config[ENV['DB'] || 'sqlite3']}
11
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
12
+
13
+ load(File.dirname(__FILE__) + "/schema.rb")
14
+
15
+ Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
16
+ $:.unshift(Test::Unit::TestCase.fixture_path)
17
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
18
+
19
+ class Test::Unit::TestCase
20
+ self.use_transactional_fixtures = true
21
+ self.use_instantiated_fixtures = false
22
+ end
23
+
24
+ require File.expand_path(File.join(File.dirname(__FILE__), '../init'))
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: railsgarden-has_draft
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ben Hughes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-16 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Allows for your ActiveRecord models to have drafts which are stored in a separate duplicate table.
17
+ email: ben@railsgarden.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - CHANGELOG
24
+ - lib/has_draft.rb
25
+ - README.rdoc
26
+ - tasks/has_draft_tasks.rake
27
+ files:
28
+ - CHANGELOG
29
+ - has_draft_plugin.sqlite3
30
+ - init.rb
31
+ - install.rb
32
+ - lib/has_draft.rb
33
+ - Manifest
34
+ - MIT-LICENSE
35
+ - Rakefile
36
+ - README.rdoc
37
+ - tasks/has_draft_tasks.rake
38
+ - test/config/database.yml
39
+ - test/fixtures/article_drafts.yml
40
+ - test/fixtures/articles.yml
41
+ - test/has_draft_test.rb
42
+ - test/models/article.rb
43
+ - test/schema.rb
44
+ - test/test_helper.rb
45
+ - uninstall.rb
46
+ - has_draft.gemspec
47
+ has_rdoc: true
48
+ homepage: http://github.com/railsgarden/has_draft
49
+ post_install_message:
50
+ rdoc_options:
51
+ - --line-numbers
52
+ - --inline-source
53
+ - --title
54
+ - Has_draft
55
+ - --main
56
+ - README.rdoc
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "1.2"
70
+ version:
71
+ requirements: []
72
+
73
+ rubyforge_project: has_draft
74
+ rubygems_version: 1.2.0
75
+ signing_key:
76
+ specification_version: 2
77
+ summary: Allows for your ActiveRecord models to have drafts which are stored in a separate duplicate table.
78
+ test_files:
79
+ - test/has_draft_test.rb
80
+ - test/test_helper.rb