kentouzu 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/.rspec +3 -0
- data/.rvmrc +80 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +79 -0
- data/README.md +105 -0
- data/Rakefile +6 -0
- data/kentouzu.gemspec +25 -0
- data/lib/generators/kentouzu/install_generator.rb +18 -0
- data/lib/generators/kentouzu/templates/create_drafts.rb +24 -0
- data/lib/kentouzu/config.rb +11 -0
- data/lib/kentouzu/controller.rb +37 -0
- data/lib/kentouzu/draft.rb +121 -0
- data/lib/kentouzu/has_drafts.rb +125 -0
- data/lib/kentouzu/version.rb +3 -0
- data/lib/kentouzu.rb +67 -0
- data/spec/kentouzu/kentouzu_spec.rb +10 -0
- data/spec/spec_helper.rb +6 -0
- metadata +114 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# This is an RVM Project .rvmrc file, used to automatically load the ruby
|
4
|
+
# development environment upon cd'ing into the directory
|
5
|
+
|
6
|
+
# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
|
7
|
+
environment_id="ruby-1.9.3-p194@kentouzu"
|
8
|
+
|
9
|
+
#
|
10
|
+
# Uncomment the following lines if you want to verify rvm version per project
|
11
|
+
#
|
12
|
+
# rvmrc_rvm_version="1.10.2" # 1.10.1 seams as a safe start
|
13
|
+
# eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
|
14
|
+
# echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
|
15
|
+
# return 1
|
16
|
+
# }
|
17
|
+
#
|
18
|
+
|
19
|
+
#
|
20
|
+
# Uncomment following line if you want options to be set only for given project.
|
21
|
+
#
|
22
|
+
# PROJECT_JRUBY_OPTS=( --1.9 )
|
23
|
+
#
|
24
|
+
# The variable PROJECT_JRUBY_OPTS requires the following to be run in shell:
|
25
|
+
#
|
26
|
+
# chmod +x ${rvm_path}/hooks/after_use_jruby_opts
|
27
|
+
#
|
28
|
+
|
29
|
+
#
|
30
|
+
# First we attempt to load the desired environment directly from the environment
|
31
|
+
# file. This is very fast and efficient compared to running through the entire
|
32
|
+
# CLI and selector. If you want feedback on which environment was used then
|
33
|
+
# insert the word 'use' after --create as this triggers verbose mode.
|
34
|
+
#
|
35
|
+
if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
|
36
|
+
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
|
37
|
+
then
|
38
|
+
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
|
39
|
+
|
40
|
+
if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]
|
41
|
+
then
|
42
|
+
. "${rvm_path:-$HOME/.rvm}/hooks/after_use"
|
43
|
+
fi
|
44
|
+
else
|
45
|
+
# If the environment file has not yet been created, use the RVM CLI to select.
|
46
|
+
if ! rvm --create "$environment_id"
|
47
|
+
then
|
48
|
+
echo "Failed to create RVM environment '${environment_id}'."
|
49
|
+
return 1
|
50
|
+
fi
|
51
|
+
fi
|
52
|
+
|
53
|
+
#
|
54
|
+
# If you use an RVM gemset file to install a list of gems (*.gems), you can have
|
55
|
+
# it be automatically loaded. Uncomment the following and adjust the filename if
|
56
|
+
# necessary.
|
57
|
+
#
|
58
|
+
# filename=".gems"
|
59
|
+
# if [[ -s "$filename" ]]
|
60
|
+
# then
|
61
|
+
# rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
|
62
|
+
# fi
|
63
|
+
|
64
|
+
# If you use bundler, this might be useful to you:
|
65
|
+
# if [[ -s Gemfile ]] && ! command -v bundle >/dev/null
|
66
|
+
# then
|
67
|
+
# printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n"
|
68
|
+
# gem install bundler
|
69
|
+
# fi
|
70
|
+
# if [[ -s Gemfile ]] && command -v bundle
|
71
|
+
# then
|
72
|
+
# bundle install
|
73
|
+
# fi
|
74
|
+
|
75
|
+
if [[ $- == *i* ]] # check for interactive shells
|
76
|
+
then
|
77
|
+
echo "Using: $(tput setaf 2)$GEM_HOME$(tput sgr0)" # show the user the ruby and gemset they are using in green
|
78
|
+
else
|
79
|
+
echo "Using: $GEM_HOME" # don't use colors in interactive shells
|
80
|
+
fi
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
kentouzu (0.0.1)
|
5
|
+
activerecord (~> 3.0)
|
6
|
+
railties (~> 3.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
actionpack (3.2.8)
|
12
|
+
activemodel (= 3.2.8)
|
13
|
+
activesupport (= 3.2.8)
|
14
|
+
builder (~> 3.0.0)
|
15
|
+
erubis (~> 2.7.0)
|
16
|
+
journey (~> 1.0.4)
|
17
|
+
rack (~> 1.4.0)
|
18
|
+
rack-cache (~> 1.2)
|
19
|
+
rack-test (~> 0.6.1)
|
20
|
+
sprockets (~> 2.1.3)
|
21
|
+
activemodel (3.2.8)
|
22
|
+
activesupport (= 3.2.8)
|
23
|
+
builder (~> 3.0.0)
|
24
|
+
activerecord (3.2.8)
|
25
|
+
activemodel (= 3.2.8)
|
26
|
+
activesupport (= 3.2.8)
|
27
|
+
arel (~> 3.0.2)
|
28
|
+
tzinfo (~> 0.3.29)
|
29
|
+
activesupport (3.2.8)
|
30
|
+
i18n (~> 0.6)
|
31
|
+
multi_json (~> 1.0)
|
32
|
+
arel (3.0.2)
|
33
|
+
builder (3.0.4)
|
34
|
+
diff-lcs (1.1.3)
|
35
|
+
erubis (2.7.0)
|
36
|
+
hike (1.2.1)
|
37
|
+
i18n (0.6.1)
|
38
|
+
journey (1.0.4)
|
39
|
+
json (1.7.5)
|
40
|
+
multi_json (1.3.6)
|
41
|
+
rack (1.4.1)
|
42
|
+
rack-cache (1.2)
|
43
|
+
rack (>= 0.4)
|
44
|
+
rack-ssl (1.3.2)
|
45
|
+
rack
|
46
|
+
rack-test (0.6.2)
|
47
|
+
rack (>= 1.0)
|
48
|
+
railties (3.2.8)
|
49
|
+
actionpack (= 3.2.8)
|
50
|
+
activesupport (= 3.2.8)
|
51
|
+
rack-ssl (~> 1.3.2)
|
52
|
+
rake (>= 0.8.7)
|
53
|
+
rdoc (~> 3.4)
|
54
|
+
thor (>= 0.14.6, < 2.0)
|
55
|
+
rake (0.9.2.2)
|
56
|
+
rdoc (3.12)
|
57
|
+
json (~> 1.4)
|
58
|
+
rspec (2.11.0)
|
59
|
+
rspec-core (~> 2.11.0)
|
60
|
+
rspec-expectations (~> 2.11.0)
|
61
|
+
rspec-mocks (~> 2.11.0)
|
62
|
+
rspec-core (2.11.1)
|
63
|
+
rspec-expectations (2.11.3)
|
64
|
+
diff-lcs (~> 1.1.3)
|
65
|
+
rspec-mocks (2.11.3)
|
66
|
+
sprockets (2.1.3)
|
67
|
+
hike (~> 1.2)
|
68
|
+
rack (~> 1.0)
|
69
|
+
tilt (~> 1.1, != 1.3.0)
|
70
|
+
thor (0.16.0)
|
71
|
+
tilt (1.3.3)
|
72
|
+
tzinfo (0.3.34)
|
73
|
+
|
74
|
+
PLATFORMS
|
75
|
+
ruby
|
76
|
+
|
77
|
+
DEPENDENCIES
|
78
|
+
kentouzu!
|
79
|
+
rspec
|
data/README.md
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# Kentouzu
|
2
|
+
|
3
|
+
Kentouzu is a Ruby gem that lets you create draft versions of your ActiveRecord models upon saving. If you're developing a publishing approval queue then Kentouzu just might be what you need. It's heavily based off the wonderful [paper_trail](https://github.com/airblade/paper_trail) gem. In fact, much of the code for this gem was pretty much lifted line for line from paper_trail (because it works beautifully). You should definitely check out paper_trail and it's source. It's a nice clean example of a gem that hooks into Rails.
|
4
|
+
|
5
|
+
## Rails Version
|
6
|
+
|
7
|
+
This gem has only been tested on Rails 3.2. There is no reason that I am aware of that would prevent it from working on all versions of Rails 3 (and Rails 4 when it is released). As Kentouzu is based on the Rails 3 branch of paper_trail it's very unlikely that it will work with Rails 2.3.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add the gem to your project's Gemfile:
|
12
|
+
|
13
|
+
gem 'kentouzu'
|
14
|
+
|
15
|
+
Generate a migration for the drafts table:
|
16
|
+
|
17
|
+
rails g kentouzu:install
|
18
|
+
|
19
|
+
Run the migration:
|
20
|
+
|
21
|
+
rake db:migrate
|
22
|
+
|
23
|
+
Add `has_drafts` to the models you want to have drafts on.
|
24
|
+
|
25
|
+
## API Summary
|
26
|
+
|
27
|
+
When you call `has_drafts` in your model you get the following methods:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
class Widget < ActiveRecord::Base
|
31
|
+
has_drafts # you can pass various options here
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns this widget's drafts.
|
35
|
+
# You can customize the name of this association.
|
36
|
+
widget.drafts
|
37
|
+
|
38
|
+
# Return the draft this widget was reified from, or nil if it is live.
|
39
|
+
# You can customize the name of this method.
|
40
|
+
widget.draft
|
41
|
+
|
42
|
+
# Returns all "new" drafts for the model. These drafts were not created from existing instances of the model or from previous drafts.
|
43
|
+
# You can customize the name of this method.
|
44
|
+
Widget.new_drafts
|
45
|
+
```
|
46
|
+
|
47
|
+
The `Draft` class has the following methods:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
# Returns all drafts created by the `create` event.
|
51
|
+
Draft.creates
|
52
|
+
|
53
|
+
# Returns all drafts created by the `update` event.
|
54
|
+
Draft.updates
|
55
|
+
```
|
56
|
+
|
57
|
+
And a `Draft` instance has these methods:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
# Return the object held by the draft.
|
61
|
+
draft.reify(options = {})
|
62
|
+
|
63
|
+
# Reify the draft and then destroy it.
|
64
|
+
widget.approve
|
65
|
+
|
66
|
+
# Destroy the draft.
|
67
|
+
draft.reject
|
68
|
+
```
|
69
|
+
|
70
|
+
More on this later!
|
71
|
+
|
72
|
+
## Basic Usage
|
73
|
+
|
74
|
+
More on this later!
|
75
|
+
|
76
|
+
## Contributing
|
77
|
+
|
78
|
+
If you feel like you can add something useful to Kentouzu then don't hesitate to contribute! To make sure your fix/feature has a high chance of being included, please do the following:
|
79
|
+
|
80
|
+
1. Fork the repo.
|
81
|
+
|
82
|
+
2. Run the tests. I will only take pull requests with passing tests, and it's great to know that you have a clean slate: `bundle && rake`
|
83
|
+
|
84
|
+
3. Add a test for your change. Only adding tests for existing code, refactoring, and documentation changes require no new tests. If you are adding functionality or fixing a bug, you need a test!
|
85
|
+
|
86
|
+
4. Make the test pass.
|
87
|
+
|
88
|
+
5. Push to your fork and submit a pull request.
|
89
|
+
|
90
|
+
I can't guarantee that I will accept the change, but if I don't I will be sure to let you know why!
|
91
|
+
|
92
|
+
Some things that will increase the chance that your pull request is accepted, taken straight from the Ruby on Rails guide:
|
93
|
+
|
94
|
+
* Use Rails idioms and helpers
|
95
|
+
* Include tests that fail without your code, and pass with it
|
96
|
+
* Update the documentation, guides, or whatever is affected by your contribution
|
97
|
+
|
98
|
+
Yes, I am well aware of the irony of asking for tests when there are effectively none right now. This gem is a work in progress.
|
99
|
+
|
100
|
+
## A Note of Warning
|
101
|
+
|
102
|
+
This gem overwrites the ActiveRecord save method. In isolation this is usually harmless. But, in combination with other gems that do the same, unpredictable behavior may result. As always, use caution, and be aware of what this gem and any others you use actually do before including it in an important project.
|
103
|
+
|
104
|
+
## Kentouzu?
|
105
|
+
"検討図" (けんとうず, kentouzu) means "draft" or "plan" in Japanese. Since "drafts" was already taken as a gem name, an appropriate Japanese word seemed like a good idea.
|
data/Rakefile
ADDED
data/kentouzu.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'kentouzu/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'kentouzu'
|
7
|
+
s.version = Kentouzu::VERSION
|
8
|
+
s.authors = ['Sean Eshbaugh']
|
9
|
+
s.email = ['seaneshbaugh@gmail.com']
|
10
|
+
s.homepage = 'http://seaneshbaugh.com/'
|
11
|
+
s.summary = 'Add drafts to ActiveRecord models.'
|
12
|
+
s.description = 'Add drafts to ActiveRecord models.'
|
13
|
+
|
14
|
+
s.rubyforge_project = 'kentouzu'
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ['lib']
|
20
|
+
|
21
|
+
s.add_dependency 'railties', '~> 3.0'
|
22
|
+
s.add_dependency 'activerecord', '~> 3.0'
|
23
|
+
|
24
|
+
s.add_development_dependency 'rspec'
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
require 'rails/generators/active_record/migration'
|
4
|
+
|
5
|
+
module Kentouzu
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
7
|
+
include Rails::Generators::Migration
|
8
|
+
extend ActiveRecord::Generators::Migration
|
9
|
+
|
10
|
+
source_root File.expand_path('../templates', __FILE__)
|
11
|
+
|
12
|
+
desc 'Generates (but does not run) a migration to add a drafts table.'
|
13
|
+
|
14
|
+
def create_migration_file
|
15
|
+
migration_template 'create_drafts.rb', 'db/migrate/create_drafts.rb'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class CreateDrafts < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :drafts do |t|
|
4
|
+
t.string :item_type, :null => false
|
5
|
+
t.integer :item_id
|
6
|
+
t.string :event, :null => false
|
7
|
+
t.string :source_type
|
8
|
+
t.string :source_id
|
9
|
+
t.text :object
|
10
|
+
t.datetime :created_at
|
11
|
+
t.datetime :updated_at
|
12
|
+
end
|
13
|
+
|
14
|
+
change_table :drafts do |t|
|
15
|
+
t.index :item_type
|
16
|
+
t.index :item_id
|
17
|
+
t.index :event
|
18
|
+
t.index :source_type
|
19
|
+
t.index :source_id
|
20
|
+
t.index :created_at
|
21
|
+
t.index :updated_at
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Kentouzu
|
2
|
+
module Controller
|
3
|
+
def self.included base
|
4
|
+
base.before_filter :set_drafts_source
|
5
|
+
base.before_filter :set_drafts_controller_info
|
6
|
+
base.before_filter :set_drafts_enabled_for_controller
|
7
|
+
end
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def user_for_drafts
|
12
|
+
current_user rescue nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def info_for_drafts
|
16
|
+
{}
|
17
|
+
end
|
18
|
+
|
19
|
+
def drafts_enabled_for_controller
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def set_drafts_enabled_for_controller
|
26
|
+
::Kentouzu.enabled_for_controller = drafts_enabled_for_controller
|
27
|
+
end
|
28
|
+
|
29
|
+
def set_drafts_source
|
30
|
+
::Kentouzu.source = user_for_drafts
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_drafts_controller_info
|
34
|
+
::Kentouzu.controller_info = info_for_drafts
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
class Draft < ActiveRecord::Base
|
2
|
+
attr_accessible :item_type, :item_id, :event, :source_type, :source_id, :object
|
3
|
+
|
4
|
+
belongs_to :item, :polymorphic => true
|
5
|
+
|
6
|
+
belongs_to :source, :polymorphic => true
|
7
|
+
|
8
|
+
validates_presence_of :event
|
9
|
+
|
10
|
+
def self.with_item_keys item_type, item_id
|
11
|
+
scoped :conditions => { :item_type => item_type, :item_id => item_id }
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.creates
|
15
|
+
where :event => 'create'
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.updates
|
19
|
+
where :event => 'update'
|
20
|
+
end
|
21
|
+
|
22
|
+
scope :subsequent, lambda { |draft| where(["#{self.primary_key} > ?", draft]).order("#{self.primary_key} ASC") }
|
23
|
+
|
24
|
+
scope :preceding, lambda { |draft| where(["#{self.primary_key} < ?}", draft]).order("#{self.primary_key} DESC") }
|
25
|
+
|
26
|
+
scope :following, lambda { |timestamp| where(["#{Kentouzu.timestamp_field} > ?"], timestamp).order("#{Kentouzu.timestamp_field} ASC, #{self.primary_key} ASC") }
|
27
|
+
|
28
|
+
scope :between, lambda { |start_time, end_time| where(["#{Kentouzu.timestamp_field} > ? AND #{Kentouzu.timestamp_field} < ?", start_time, end_time]).order("#{Kentouzu.timestamp_field} ASC, #{self.primary_key} ASC") }
|
29
|
+
|
30
|
+
def reify options = {}
|
31
|
+
without_identity_map do
|
32
|
+
options[:has_one] = 3 if options[:has_one] == true
|
33
|
+
options.reverse_merge! :has_one => false
|
34
|
+
|
35
|
+
unless object.nil?
|
36
|
+
#This appears to be necessary if for some reason the draft's model hasn't been loaded (such as when done in the console).
|
37
|
+
require self.item_type.downcase
|
38
|
+
|
39
|
+
loaded_object = YAML::load object
|
40
|
+
|
41
|
+
if item
|
42
|
+
model = item
|
43
|
+
else
|
44
|
+
inheritance_column_name = item_type.constantize.inheritance_column
|
45
|
+
|
46
|
+
class_name = loaded_object.respond_to?(inheritance_column_name.to_sym) ? inheritance_column_name : item_type
|
47
|
+
|
48
|
+
klass = class_name.constantize
|
49
|
+
|
50
|
+
model = klass.new
|
51
|
+
end
|
52
|
+
|
53
|
+
loaded_object.attributes.each do |key, value|
|
54
|
+
if model.respond_to?("#{key}=")
|
55
|
+
model.send :write_attribute, key.to_sym, value
|
56
|
+
else
|
57
|
+
logger.warn "Attribute #{key} does not exist on #{item_type} (Draft ID: #{id})."
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
model.send "#{model.class.draft_association_name}=", self
|
62
|
+
|
63
|
+
unless options[:has_one] == false
|
64
|
+
reify_has_ones model, options[:has_one]
|
65
|
+
end
|
66
|
+
|
67
|
+
model
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def approve
|
73
|
+
model = self.reify
|
74
|
+
|
75
|
+
if model
|
76
|
+
model.without_drafts :save
|
77
|
+
|
78
|
+
if event == 'update'
|
79
|
+
previous_drafts = Draft.where(["item_type = ? AND item_id = ? AND created_at <= ? AND id <= ?", model.class.to_s, model.id, self.created_at.strftime('%Y-%m-%d %H:%M:%S'), self.id])
|
80
|
+
|
81
|
+
previous_drafts.each do |previous_draft|
|
82
|
+
previous_draft.delete
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
self.destroy
|
88
|
+
|
89
|
+
model
|
90
|
+
end
|
91
|
+
|
92
|
+
def reject
|
93
|
+
self.destroy
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def without_identity_map &block
|
99
|
+
if defined?(ActiveRecord::IdentityMap) && ActiveRecord::IdentityMap.respond_to?(:without)
|
100
|
+
ActiveRecord::IdentityMap.without &block
|
101
|
+
else
|
102
|
+
block.call
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def reify_has_ones model, lookback
|
107
|
+
model.class.reflect_on_all_associations(:has_one).each do |association|
|
108
|
+
child = model.send association.name
|
109
|
+
|
110
|
+
if child.respond_to? :draft_at
|
111
|
+
if (child_as_it_was = child.draft_at(send(Kentouzu.timestamp_field) - lookback.seconds))
|
112
|
+
child_as_it_was.attributes.each do |key, value|
|
113
|
+
model.send(association.name).send :write_attribute, key.to_sym, value rescue nil
|
114
|
+
end
|
115
|
+
else
|
116
|
+
model.send "#{association.name}=", nil
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module Kentouzu
|
2
|
+
module Model
|
3
|
+
def self.included(base)
|
4
|
+
base.send :extend, ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def has_drafts options = {}
|
9
|
+
send :include, InstanceMethods
|
10
|
+
|
11
|
+
class_attribute :draft_association_name
|
12
|
+
self.draft_association_name = options[:draft] || :draft
|
13
|
+
|
14
|
+
attr_accessor self.draft_association_name
|
15
|
+
|
16
|
+
class_attribute :draft_class_name
|
17
|
+
self.draft_class_name = options[:class_name] || 'Draft'
|
18
|
+
|
19
|
+
class_attribute :ignore
|
20
|
+
self.ignore = ([options[:ignore]].flatten.compact || []).map &:to_s
|
21
|
+
|
22
|
+
class_attribute :if_condition
|
23
|
+
self.if_condition = options[:if]
|
24
|
+
|
25
|
+
class_attribute :unless_condition
|
26
|
+
self.unless_condition = options[:unless]
|
27
|
+
|
28
|
+
class_attribute :skip
|
29
|
+
self.skip = ([options[:skip]].flatten.compact || []).map &:to_s
|
30
|
+
|
31
|
+
class_attribute :only
|
32
|
+
self.only = ([options[:only]].flatten.compact || []).map &:to_s
|
33
|
+
|
34
|
+
class_attribute :drafts_enabled_for_model
|
35
|
+
self.drafts_enabled_for_model = true
|
36
|
+
|
37
|
+
class_attribute :drafts_association_name
|
38
|
+
self.drafts_association_name = options[:drafts] || :drafts
|
39
|
+
|
40
|
+
has_many self.drafts_association_name,
|
41
|
+
:class_name => draft_class_name,
|
42
|
+
:as => :item,
|
43
|
+
:order => "#{Kentouzu.timestamp_field} ASC, #{self.draft_class_name.constantize.primary_key} ASC",
|
44
|
+
:dependent => :destroy
|
45
|
+
|
46
|
+
define_singleton_method "new_#{drafts_association_name.to_s}".to_sym do
|
47
|
+
Draft.where(:item_type => self.name, :event => 'create')
|
48
|
+
end
|
49
|
+
|
50
|
+
def drafts_off
|
51
|
+
self.drafts_enabled_for_model = false
|
52
|
+
end
|
53
|
+
|
54
|
+
def drafts_on
|
55
|
+
self.drafts_enabled_for_model = true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module InstanceMethods
|
61
|
+
def self.included(base)
|
62
|
+
default_save = base.instance_method(:save)
|
63
|
+
|
64
|
+
base.send :define_method, :save do
|
65
|
+
if switched_on? && save_draft?
|
66
|
+
puts "calling new save"
|
67
|
+
|
68
|
+
draft = Draft.new(:item_type => self.class.to_s, :item_id => self.id, :event => self.persisted? ? "update" : "create", :source_type => Kentouzu.source.present? ? Kentouzu.source.class.to_s : nil, :source_id => Kentouzu.source.present? ? Kentouzu.source.id : nil, :object => self.to_yaml)
|
69
|
+
|
70
|
+
draft.save
|
71
|
+
else
|
72
|
+
puts "calling default save"
|
73
|
+
|
74
|
+
puts self.inspect
|
75
|
+
|
76
|
+
default_save.bind(self).()
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def live?
|
82
|
+
source_draft.nil?
|
83
|
+
end
|
84
|
+
|
85
|
+
def draft_at timestamp, reify_options = {}
|
86
|
+
v = send(self.class.versions_association_name).following(timestamp).first
|
87
|
+
v ? v.reify(reify_options) : self
|
88
|
+
end
|
89
|
+
|
90
|
+
def without_drafts method = nil
|
91
|
+
drafts_were_enabled = self.drafts_enabled_for_model
|
92
|
+
|
93
|
+
puts "drafts_were_enabled #{drafts_were_enabled}"
|
94
|
+
|
95
|
+
self.class.drafts_off
|
96
|
+
|
97
|
+
puts "self.drafts_enabled_for_model #{self.drafts_enabled_for_model}"
|
98
|
+
|
99
|
+
puts method
|
100
|
+
|
101
|
+
method ? method.to_proc.call(self) : yield
|
102
|
+
ensure
|
103
|
+
self.class.drafts_on if drafts_were_enabled
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def draft_class
|
109
|
+
draft_class_name.constantize
|
110
|
+
end
|
111
|
+
|
112
|
+
def source_draft
|
113
|
+
send self.class.draft_association_name
|
114
|
+
end
|
115
|
+
|
116
|
+
def switched_on?
|
117
|
+
Kentouzu.enabled? && Kentouzu.enabled_for_controller? && self.class.drafts_enabled_for_model
|
118
|
+
end
|
119
|
+
|
120
|
+
def save_draft?
|
121
|
+
(if_condition.blank? || if_condition.call(self)) && !unless_condition.try(:call, self)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
data/lib/kentouzu.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
require 'kentouzu/config'
|
5
|
+
require 'kentouzu/controller'
|
6
|
+
require 'kentouzu/has_drafts'
|
7
|
+
require 'kentouzu/draft'
|
8
|
+
|
9
|
+
module Kentouzu
|
10
|
+
def self.enabled= value
|
11
|
+
Kentouzu.config.enabled = value
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.enabled?
|
15
|
+
!!Kentouzu.config.enabled
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.enabled_for_controller= value
|
19
|
+
drafts_store[:request_enabled_for_controller] = value
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.enabled_for_controller?
|
23
|
+
!!drafts_store[:request_enabled_for_controller]
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.timestamp_field= field_name
|
27
|
+
Kentouzu.config.timestamp_field = field_name
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.timestamp_field
|
31
|
+
Kentouzu.config.timestamp_field
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.source= value
|
35
|
+
drafts_store[:source] = value
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.source
|
39
|
+
drafts_store[:source]
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.controller_info= value
|
43
|
+
drafts_store[:controller_info] = value
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.controller_info
|
47
|
+
drafts_store[:controller_info]
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def self.drafts_store
|
53
|
+
Thread.current[:draft] ||= { :request_enabled_for_controller => true }
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.config
|
57
|
+
@@config ||= Kentouzu::Config.instance
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
ActiveSupport.on_load(:active_record) do
|
62
|
+
include Kentouzu::Model
|
63
|
+
end
|
64
|
+
|
65
|
+
ActiveSupport.on_load(:action_controller) do
|
66
|
+
include Kentouzu::Controller
|
67
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kentouzu
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sean Eshbaugh
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-30 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: railties
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activerecord
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '3.0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '3.0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: Add drafts to ActiveRecord models.
|
63
|
+
email:
|
64
|
+
- seaneshbaugh@gmail.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- .rspec
|
71
|
+
- .rvmrc
|
72
|
+
- CHANGELOG.md
|
73
|
+
- Gemfile
|
74
|
+
- Gemfile.lock
|
75
|
+
- README.md
|
76
|
+
- Rakefile
|
77
|
+
- kentouzu.gemspec
|
78
|
+
- lib/generators/kentouzu/install_generator.rb
|
79
|
+
- lib/generators/kentouzu/templates/create_drafts.rb
|
80
|
+
- lib/kentouzu.rb
|
81
|
+
- lib/kentouzu/config.rb
|
82
|
+
- lib/kentouzu/controller.rb
|
83
|
+
- lib/kentouzu/draft.rb
|
84
|
+
- lib/kentouzu/has_drafts.rb
|
85
|
+
- lib/kentouzu/version.rb
|
86
|
+
- spec/kentouzu/kentouzu_spec.rb
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
homepage: http://seaneshbaugh.com/
|
89
|
+
licenses: []
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options: []
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ! '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
requirements: []
|
107
|
+
rubyforge_project: kentouzu
|
108
|
+
rubygems_version: 1.8.23
|
109
|
+
signing_key:
|
110
|
+
specification_version: 3
|
111
|
+
summary: Add drafts to ActiveRecord models.
|
112
|
+
test_files:
|
113
|
+
- spec/kentouzu/kentouzu_spec.rb
|
114
|
+
- spec/spec_helper.rb
|