magic_userstamp 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/.gitignore +5 -0
- data/CHANGELOG +26 -0
- data/LICENSE +20 -0
- data/README.original +179 -0
- data/README.rdoc +64 -0
- data/Rakefile +45 -0
- data/VERSION +1 -0
- data/init.rb +12 -0
- data/lib/userstamp/config.rb +119 -0
- data/lib/userstamp/controller.rb +43 -0
- data/lib/userstamp/event.rb +63 -0
- data/lib/userstamp/magic_columns.rb +49 -0
- data/lib/userstamp/migration_helper.rb +17 -0
- data/lib/userstamp/stampable.rb +147 -0
- data/lib/userstamp/stamper.rb +41 -0
- data/lib/userstamp.rb +17 -0
- data/magic_userstamp.gemspec +124 -0
- data/rdoc/classes/Ddb/Controller/Userstamp/InstanceMethods.html +105 -0
- data/rdoc/classes/Ddb/Controller/Userstamp.html +125 -0
- data/rdoc/classes/Ddb/Controller.html +111 -0
- data/rdoc/classes/Ddb/Userstamp/MigrationHelper/InstanceMethods.html +142 -0
- data/rdoc/classes/Ddb/Userstamp/MigrationHelper.html +111 -0
- data/rdoc/classes/Ddb/Userstamp/Stampable/ClassMethods.html +222 -0
- data/rdoc/classes/Ddb/Userstamp/Stampable.html +128 -0
- data/rdoc/classes/Ddb/Userstamp/Stamper/ClassMethods.html +142 -0
- data/rdoc/classes/Ddb/Userstamp/Stamper/InstanceMethods.html +207 -0
- data/rdoc/classes/Ddb/Userstamp/Stamper.html +112 -0
- data/rdoc/classes/Ddb/Userstamp.html +121 -0
- data/rdoc/created.rid +1 -0
- data/rdoc/files/CHANGELOG.html +137 -0
- data/rdoc/files/LICENSE.html +129 -0
- data/rdoc/files/README.html +341 -0
- data/rdoc/files/lib/migration_helper_rb.html +101 -0
- data/rdoc/files/lib/stampable_rb.html +101 -0
- data/rdoc/files/lib/stamper_rb.html +101 -0
- data/rdoc/files/lib/userstamp_rb.html +101 -0
- data/rdoc/fr_class_index.html +37 -0
- data/rdoc/fr_file_index.html +33 -0
- data/rdoc/fr_method_index.html +33 -0
- data/rdoc/index.html +24 -0
- data/rdoc/rdoc-style.css +208 -0
- data/spec/compatibility_stamping_spec.rb +76 -0
- data/spec/config_spec.rb +155 -0
- data/spec/database.yml +4 -0
- data/spec/fixtures/comments.yml +16 -0
- data/spec/fixtures/people.yml +11 -0
- data/spec/fixtures/posts.yml +9 -0
- data/spec/fixtures/users.yml +7 -0
- data/spec/magic_column_spec.rb +171 -0
- data/spec/posts_controller_spec.rb +41 -0
- data/spec/resources/controllers/application_controller.rb +2 -0
- data/spec/resources/controllers/posts_controller.rb +26 -0
- data/spec/resources/controllers/users_controller.rb +12 -0
- data/spec/resources/controllers/userstamp_controller.rb +9 -0
- data/spec/resources/models/comment.rb +4 -0
- data/spec/resources/models/person.rb +4 -0
- data/spec/resources/models/ping.rb +7 -0
- data/spec/resources/models/post.rb +4 -0
- data/spec/resources/models/user.rb +4 -0
- data/spec/schema.rb +56 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +66 -0
- data/spec/stamping_spec.rb +114 -0
- data/spec/users_controller_spec.rb +33 -0
- metadata +145 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
2.0 (2-17-2008)
|
2
|
+
* [Ben Wyrosdick] - Added a migration helper that gives migration scripts a <tt>userstamps</tt>
|
3
|
+
method.
|
4
|
+
* [Marshall Roch] - Stamping can be temporarily turned off using the 'without_stamps' class
|
5
|
+
method.
|
6
|
+
Example:
|
7
|
+
Post.without_stamps do
|
8
|
+
post = Post.find(params[:id])
|
9
|
+
post.update_attributes(params[:post])
|
10
|
+
post.save
|
11
|
+
end
|
12
|
+
|
13
|
+
* Models that should receive updates made by 'stampers' now use the acts_as_stampable class
|
14
|
+
method. This sets up the belongs_to relationships and also injects private methods for use by
|
15
|
+
the individual callback filter methods.
|
16
|
+
|
17
|
+
* Models that are responsible for updating now use the acts_as_stamper class method. This
|
18
|
+
injects the stamper= and stamper methods that are thread safe and should be updated per
|
19
|
+
request by a controller.
|
20
|
+
|
21
|
+
* The Userstamp module is now meant to be included with one of your project's controllers (the
|
22
|
+
Application Controller is recommended). It creates a before filter called 'set_stampers' that
|
23
|
+
is responsible for setting all the current Stampers.
|
24
|
+
|
25
|
+
1.0 (01-18-2006)
|
26
|
+
* Initial Release
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2006-2008 DeLynn Berry
|
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/README.original
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
= Userstamp Plugin (v 2.0)
|
2
|
+
|
3
|
+
== Overview
|
4
|
+
|
5
|
+
The Userstamp Plugin extends ActiveRecord::Base[http://api.rubyonrails.com/classes/ActiveRecord/Base.html] to add automatic updating of 'creator',
|
6
|
+
'updater', and 'deleter' attributes. It is based loosely on the ActiveRecord::Timestamp[http://api.rubyonrails.com/classes/ActiveRecord/Timestamp.html] module.
|
7
|
+
|
8
|
+
Two class methods (<tt>model_stamper</tt> and <tt>stampable</tt>) are implemented in this plugin.
|
9
|
+
The <tt>model_stamper</tt> method is used in models that are responsible for creating, updating, or
|
10
|
+
deleting other objects. The <tt>stampable</tt> method is used in models that are subject to being
|
11
|
+
created, updated, or deleted by 'stampers'.
|
12
|
+
|
13
|
+
|
14
|
+
== Installation
|
15
|
+
Installation of the plugin can be done using the built in Rails plugin script. Issue the following
|
16
|
+
command from the root of your application:
|
17
|
+
|
18
|
+
script/plugin install git://github.com/delynn/userstamp.git
|
19
|
+
|
20
|
+
Once installed you will need to restart your application for the plugin to be loaded into the Rails
|
21
|
+
environment.
|
22
|
+
|
23
|
+
You might also be interested in using Piston[http://piston.rubyforge.org/index.html] to manage the
|
24
|
+
importing and future updating of this plugin.
|
25
|
+
|
26
|
+
== Usage
|
27
|
+
In this new version of the Userstamp plug-in, the assumption is that you have two different
|
28
|
+
categories of objects; those that mani˝pulate, and those that are manipulated. For those objects
|
29
|
+
that are being manipulated there's the Stampable module and for the manipulators there's the
|
30
|
+
Stamper module. There's also the actual Userstamp module for your controllers that assists in
|
31
|
+
setting up your environment on a per request basis.
|
32
|
+
|
33
|
+
To better understand how all this works, I think an example is in order. For this example we will
|
34
|
+
assume that a weblog application is comprised of User and Post objects. The first thing we need to
|
35
|
+
do is create the migrations for these objects, and the plug-in gives you a <tt>userstamps</tt>
|
36
|
+
method for very easily doing this:
|
37
|
+
|
38
|
+
class CreateUsers < ActiveRecord::Migration
|
39
|
+
def self.up
|
40
|
+
create_table :users, :force => true do |t|
|
41
|
+
t.timestamps
|
42
|
+
t.userstamps
|
43
|
+
t.name
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.down
|
48
|
+
drop_table :users
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class CreatePosts < ActiveRecord::Migration
|
53
|
+
def self.up
|
54
|
+
create_table :posts, :force => true do |t|
|
55
|
+
t.timestamps
|
56
|
+
t.userstamps
|
57
|
+
t.title
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.down
|
62
|
+
drop_table :posts
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
Second, since Users are going to manipulate other objects in our project, we'll use the
|
67
|
+
<tt>model_stamper</tt> method in our User class:
|
68
|
+
|
69
|
+
class User < ActiveRecord::Base
|
70
|
+
model_stamper
|
71
|
+
end
|
72
|
+
|
73
|
+
Finally, we need to setup a controller to set the current user of the application. It's
|
74
|
+
recommended that you do this in your ApplicationController:
|
75
|
+
|
76
|
+
class ApplicationController < ActionController::Base
|
77
|
+
include Userstamp
|
78
|
+
end
|
79
|
+
|
80
|
+
If all you are interested in is making sure all tables that have the proper columns are stamped
|
81
|
+
by the currently logged in user you can stop right here. More than likely you want all your
|
82
|
+
associations setup on your stamped objects, and that's where the <tt>stampable</tt> class method
|
83
|
+
comes in. So in our example we'll want to use this method in both our User and Post classes:
|
84
|
+
|
85
|
+
class User < ActiveRecord::Base
|
86
|
+
model_stamper
|
87
|
+
stampable
|
88
|
+
end
|
89
|
+
|
90
|
+
class Post < ActiveRecord::Base
|
91
|
+
stampable
|
92
|
+
end
|
93
|
+
|
94
|
+
Okay, so what all have we done? The <tt>model_stamper</tt> class method injects two methods into the
|
95
|
+
User class. They are #stamper= and #stamper and look like this:
|
96
|
+
|
97
|
+
def stamper=(object)
|
98
|
+
object_stamper = if object.is_a?(ActiveRecord::Base)
|
99
|
+
object.send("#{object.class.primary_key}".to_sym)
|
100
|
+
else
|
101
|
+
object
|
102
|
+
end
|
103
|
+
|
104
|
+
Thread.current["#{self.to_s.downcase}_#{self.object_id}_stamper"] = object_stamper
|
105
|
+
end
|
106
|
+
|
107
|
+
def stamper
|
108
|
+
Thread.current["#{self.to_s.downcase}_#{self.object_id}_stamper"]
|
109
|
+
end
|
110
|
+
|
111
|
+
The big change with this new version is that we are now using Thread.current to save the current
|
112
|
+
stamper so as to avoid conflict with concurrent requests.
|
113
|
+
|
114
|
+
The <tt>stampable</tt> method allows you to customize what columns will get stamped, and also
|
115
|
+
creates the +creator+, +updater+, and +deleter+ associations.
|
116
|
+
|
117
|
+
The Userstamp module that we included into our ApplicationController uses the setter method to
|
118
|
+
set which user is currently making the request. By default the 'set_stampers' method works perfectly
|
119
|
+
with the RestfulAuthentication[http://svn.techno-weenie.net/projects/plugins/restful_authentication] plug-in:
|
120
|
+
|
121
|
+
def set_stampers
|
122
|
+
User.stamper = self.current_user
|
123
|
+
end
|
124
|
+
|
125
|
+
If you aren't using ActsAsAuthenticated, then you need to create your own version of the
|
126
|
+
<tt>set_stampers</tt> method in the controller where you've included the Userstamp module.
|
127
|
+
|
128
|
+
Now, let's get back to the Stampable module (since it really is the interesting one). The Stampable
|
129
|
+
module sets up before_* filters that are responsible for setting those attributes at the appropriate
|
130
|
+
times. It also creates the belongs_to relationships for you.
|
131
|
+
|
132
|
+
If you need to customize the columns that are stamped, the <tt>stampable</tt> method can be
|
133
|
+
completely customized. Here's an quick example:
|
134
|
+
|
135
|
+
class Post < ActiveRecord::Base
|
136
|
+
acts_as_stampable :stamper_class_name => :person,
|
137
|
+
:creator_attribute => :create_user,
|
138
|
+
:updater_attribute => :update_user,
|
139
|
+
:deleter_attribute => :delete_user
|
140
|
+
end
|
141
|
+
|
142
|
+
If you are upgrading your application from the old version of Userstamp, there is a compatibility
|
143
|
+
mode to have the plug-in use the old "_by" columns by default. To enable this mode, add the
|
144
|
+
following line to the RAILS_ROOT/config/environment.rb file:
|
145
|
+
|
146
|
+
Ddb::Userstamp.compatibility_mode = true
|
147
|
+
|
148
|
+
If you are having a difficult time getting the Userstamp plug-in to work, I recommend you checkout
|
149
|
+
the sample application that I created. You can find this application on GitHub[http://github.com/delynn/userstamp_sample]
|
150
|
+
|
151
|
+
== Uninstall
|
152
|
+
Uninstalling the plugin can be done using the built in Rails plugin script. Issue the following
|
153
|
+
command from the root of your application:
|
154
|
+
|
155
|
+
script/plugin remove userstamp
|
156
|
+
|
157
|
+
|
158
|
+
== Documentation
|
159
|
+
RDoc has been run on the plugin directory and is available in the doc directory.
|
160
|
+
|
161
|
+
|
162
|
+
== Running Unit Tests
|
163
|
+
There are extensive unit tests in the "test" directory of the plugin. These test can be run
|
164
|
+
individually by executing the following command from the userstamp directory:
|
165
|
+
|
166
|
+
ruby test/compatibility_stamping_test.rb
|
167
|
+
ruby test/stamping_test.rb
|
168
|
+
ruby test/userstamp_controller_test.rb
|
169
|
+
|
170
|
+
|
171
|
+
== Bugs & Feedback
|
172
|
+
Bug reports and feedback are welcome via my delynn+userstamp@gmail.com email address. I also
|
173
|
+
encouraged everyone to clone the git repository and make modifications--I'll be more than happy
|
174
|
+
to merge any changes from other people's branches that would be beneficial to the whole project.
|
175
|
+
|
176
|
+
|
177
|
+
== Credits and Special Thanks
|
178
|
+
The original idea for this plugin came from the Rails Wiki article entitled
|
179
|
+
{Extending ActiveRecord}[http://wiki.rubyonrails.com/rails/pages/ExtendingActiveRecordExample].
|
data/README.rdoc
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
= MagicUserstamp
|
2
|
+
|
3
|
+
== Install
|
4
|
+
|
5
|
+
=== as a plugin
|
6
|
+
ruby script/plugin install git://github.com/akm/magic_userstamp.git
|
7
|
+
|
8
|
+
=== as a gem
|
9
|
+
insert following line to config/environment.rb
|
10
|
+
config.gem 'magic_userstamp', :version => '0.1.0'
|
11
|
+
and
|
12
|
+
$ sudo rake gems:install
|
13
|
+
|
14
|
+
Or install gem manually
|
15
|
+
|
16
|
+
$ sudo gem install gemcutter
|
17
|
+
$ sudo gem tumble
|
18
|
+
$ sudo gem install magic_userstamp
|
19
|
+
|
20
|
+
== Setting
|
21
|
+
make config/initializers/magic_userstamp.rb
|
22
|
+
|
23
|
+
The most simple setting
|
24
|
+
Userstamp::Config.setup.defaults
|
25
|
+
|
26
|
+
Specify User class name
|
27
|
+
Userstamp::Config.setup.defaults(:stamper_class_name => 'AdminUser')
|
28
|
+
|
29
|
+
Actually
|
30
|
+
Userstamp::Config.setup.defaults
|
31
|
+
means
|
32
|
+
Userstamp.config.setup do |config|
|
33
|
+
config.with_options(:stamper_class_name => 'User') do |c|
|
34
|
+
c.on(:create , :creator_id)
|
35
|
+
c.on(:update , :updater_id)
|
36
|
+
c.on(:destroy, :deleter_id)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
Specify User class name and creator/updater columns
|
42
|
+
Userstamp.config.setup do |config|
|
43
|
+
config.with_options(:stamper_class_name => 'Person') do |c|
|
44
|
+
c.on(:create , :creator_person_id)
|
45
|
+
c.on(:update , :updater_person_id)
|
46
|
+
c.on(:destroy, :deleter_person_id)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Specify target stampable class names
|
51
|
+
Userstamp.config.setup do |config|
|
52
|
+
config.defaults(:stampable_class_names => %w(Book Schedule))
|
53
|
+
|
54
|
+
Specify target stampable class names and columns
|
55
|
+
Userstamp.config.setup do |config|
|
56
|
+
config.with_options(:stampable_class_names => %w(Book Schedule)) do |c|
|
57
|
+
c.on(:create , :creator_user_id)
|
58
|
+
c.on(:update , :updater_user_id)
|
59
|
+
c.on(:destroy, :deleter_user_id)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
-----
|
64
|
+
Copyright (c) 2009 'Takeshi AKIMA, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "magic_userstamp"
|
8
|
+
gem.summary = %Q{creator_id/updater_id/deleter_id support with setting outside models}
|
9
|
+
gem.description = %Q{This Rails plugin extends ActiveRecord::Base to add automatic updating of created_by and updated_by attributes of your models in much the same way that the ActiveRecord::Timestamp module updates created_(at/on) and updated_(at/on) attributes.}
|
10
|
+
gem.email = "akm2000@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/akm/magic_userstamp"
|
12
|
+
gem.authors = ["akimatter"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'spec/rake/spectask'
|
22
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
23
|
+
spec.libs << 'lib' << 'spec'
|
24
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
25
|
+
end
|
26
|
+
|
27
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
30
|
+
spec.rcov = true
|
31
|
+
end
|
32
|
+
|
33
|
+
task :spec => :check_dependencies
|
34
|
+
|
35
|
+
task :default => :spec
|
36
|
+
|
37
|
+
require 'rake/rdoctask'
|
38
|
+
Rake::RDocTask.new do |rdoc|
|
39
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
40
|
+
|
41
|
+
rdoc.rdoc_dir = 'rdoc'
|
42
|
+
rdoc.title = "magic_userstamp #{version}"
|
43
|
+
rdoc.rdoc_files.include('README*')
|
44
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
45
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/init.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'userstamp'
|
3
|
+
# コントローラへは自身でincludeしてください。
|
4
|
+
# ActionController::Base.send(:include, Userstamp::Controller) if defined?(ActionController)
|
5
|
+
ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, Userstamp::MigrationHelper)
|
6
|
+
if defined?(ActiveRecord)
|
7
|
+
ActiveRecord::Base.module_eval do
|
8
|
+
include Userstamp::Stampable
|
9
|
+
include Userstamp::Stamper
|
10
|
+
include Userstamp::MagicColumns # mest be included after Userstamp::Stampable
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'userstamp'
|
3
|
+
|
4
|
+
module Userstamp
|
5
|
+
|
6
|
+
def self.config
|
7
|
+
Config.instance
|
8
|
+
end
|
9
|
+
|
10
|
+
class Config
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def instance
|
14
|
+
@instance || setup
|
15
|
+
end
|
16
|
+
|
17
|
+
def setup
|
18
|
+
@instance = Config.new
|
19
|
+
yield(@instance) if block_given?
|
20
|
+
@instance
|
21
|
+
end
|
22
|
+
|
23
|
+
def clear
|
24
|
+
@instance = nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :patterns
|
29
|
+
attr_accessor :with_destroy
|
30
|
+
attr_accessor :verbose
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@patterns = []
|
34
|
+
@with_destroy = defined?(Caboose::Acts::Paranoid)
|
35
|
+
end
|
36
|
+
|
37
|
+
def pattern_for(klass, column_name)
|
38
|
+
patterns.detect{|pattern| pattern.stampable?(klass, column_name)}
|
39
|
+
end
|
40
|
+
|
41
|
+
def on(event_name, column_name, options = nil)
|
42
|
+
result = Pattern.new(event_name, column_name, options)
|
43
|
+
patterns << result
|
44
|
+
result
|
45
|
+
end
|
46
|
+
|
47
|
+
def defaults(options = nil)
|
48
|
+
on(:create , :creator_id, options)
|
49
|
+
on(:update , :updater_id, options)
|
50
|
+
on(:destroy, :deleter_id, options) if with_destroy
|
51
|
+
end
|
52
|
+
|
53
|
+
def compatibles(options = nil)
|
54
|
+
on(:create , :created_by, options)
|
55
|
+
on(:update , :updated_by, options)
|
56
|
+
on(:destroy, :deleted_by, options) if with_destroy
|
57
|
+
end
|
58
|
+
|
59
|
+
def verbose?(klass, column_name)
|
60
|
+
case verbose
|
61
|
+
when Hash then
|
62
|
+
verbose_match?(verbose, klass, column_name)
|
63
|
+
when Array then
|
64
|
+
verbose.any?{|setting| verbose_match?(setting, klass, column_name)}
|
65
|
+
else
|
66
|
+
!!verbose
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def verbose_match?(setting, klass, column_name)
|
73
|
+
classes = []
|
74
|
+
columns = []
|
75
|
+
{:classes => classes, :columns => columns}.each do |key, dest|
|
76
|
+
if value = setting[key]
|
77
|
+
dest.concat(value.is_a?(Array) ? value : [value])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
classes = classes.map{|s| s.to_s}
|
81
|
+
columns = columns.map{|s| s.to_s}
|
82
|
+
(classes.empty? || classes.include?(klass.name)) &&
|
83
|
+
(columns.empty? || columns.include?(column_name.to_s))
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
class Pattern
|
88
|
+
attr_reader :event_name, :column_name, :stampable_class_names
|
89
|
+
attr_reader :stamper_class_name, :stamper_attr_name
|
90
|
+
attr_reader :options_for_stampable_on
|
91
|
+
|
92
|
+
def initialize(event_name, column_name, options = nil)
|
93
|
+
@event_name = event_name
|
94
|
+
@column_name = column_name
|
95
|
+
options = {
|
96
|
+
:stampable_class_names => nil,
|
97
|
+
:stamper_class_name => 'User',
|
98
|
+
:stamper_attr_name => nil # sholuld not be only 'id' but PK column name
|
99
|
+
}.update(options || {})
|
100
|
+
@stampable_class_names = options.delete(:stampable_class_names)
|
101
|
+
Userstamp.raise_unless_valid_options_for_stampable_on(options)
|
102
|
+
@options_for_stampable_on = options
|
103
|
+
@stamper_class_name = options[:stamper_class_name]
|
104
|
+
@stamper_attr_name = options[:stamper_attr_name]
|
105
|
+
end
|
106
|
+
|
107
|
+
def stampable?(klass, column_name)
|
108
|
+
(stampable_class_names.nil? ? true : stampable_class_names.include?(klass.name)) &&
|
109
|
+
(column_name.to_s == self.column_name.to_s)
|
110
|
+
end
|
111
|
+
|
112
|
+
def args_for_stampable_on(column_name = nil)
|
113
|
+
[event_name, {:attribute => column_name || self.column_name}.update(@options_for_stampable_on)]
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'userstamp'
|
2
|
+
|
3
|
+
module Userstamp
|
4
|
+
module Controller
|
5
|
+
# The Userstamp module, when included into a controller, adds a before filter
|
6
|
+
# (named <tt>set_stamper</tt>) and an after filter (name <tt>reset_stamper</tt>).
|
7
|
+
# These methods assume a couple of things, but can be re-implemented in your
|
8
|
+
# controller to better suite your application.
|
9
|
+
#
|
10
|
+
# See the documentation for <tt>set_stamper</tt> and <tt>reset_stamper</tt> for
|
11
|
+
# specific implementation details.
|
12
|
+
|
13
|
+
def self.included(base) # :nodoc:
|
14
|
+
base.send :include, InstanceMethods
|
15
|
+
base.before_filter :set_stamper
|
16
|
+
base.after_filter :reset_stamper
|
17
|
+
end
|
18
|
+
|
19
|
+
module InstanceMethods
|
20
|
+
private
|
21
|
+
# The <tt>set_stamper</tt> method as implemented here assumes a couple
|
22
|
+
# of things. First, that you are using a +User+ model as the stamper
|
23
|
+
# and second that your controller has a <tt>current_user</tt> method
|
24
|
+
# that contains the currently logged in stamper. If either of these
|
25
|
+
# are not the case in your application you will want to manually add
|
26
|
+
# your own implementation of this method to the private section of
|
27
|
+
# the controller where you are including the Userstamp module.
|
28
|
+
def set_stamper
|
29
|
+
User.stamper = self.current_user
|
30
|
+
end
|
31
|
+
|
32
|
+
# The <tt>reset_stamper</tt> method as implemented here assumes that a
|
33
|
+
# +User+ model is being used as the stamper. If this is not the case then
|
34
|
+
# you will need to manually add your own implementation of this method to
|
35
|
+
# the private section of the controller where you are including the
|
36
|
+
# Userstamp module.
|
37
|
+
def reset_stamper
|
38
|
+
User.reset_stamper
|
39
|
+
end
|
40
|
+
#end private
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'userstamp'
|
3
|
+
|
4
|
+
module Userstamp
|
5
|
+
|
6
|
+
class Event
|
7
|
+
attr_reader :name, :actor, :actual_hook, :after_callback
|
8
|
+
attr_reader:default_attribute, :default_attribute_compatible
|
9
|
+
|
10
|
+
def initialize(name, actor, default_attribute_compatible, options = nil)
|
11
|
+
@name, @actor = name.to_s, actor.to_s
|
12
|
+
@default_attribute = "#{@actor}_id"
|
13
|
+
@default_attribute_compatible = default_attribute_compatible
|
14
|
+
options = {
|
15
|
+
:actual_hook => "before_#{@name.to_s}"
|
16
|
+
}.update(options || {})
|
17
|
+
@actual_hook = options[:actual_hook]
|
18
|
+
@after_callback = options[:after_callback]
|
19
|
+
end
|
20
|
+
|
21
|
+
class << self
|
22
|
+
def create(name, actor, default_attribute_compatible, options = nil, &block)
|
23
|
+
result = self.new(name, actor, default_attribute_compatible, options, &block)
|
24
|
+
@name_hash ||= HashWithIndifferentAccess.new
|
25
|
+
@name_hash[name] = result
|
26
|
+
@instances ||= []
|
27
|
+
@instances << result
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
def [](event_name)
|
32
|
+
raise_unless_valid_name(event_name)
|
33
|
+
@name_hash[event_name]
|
34
|
+
end
|
35
|
+
|
36
|
+
def each(&block)
|
37
|
+
return unless block
|
38
|
+
(@instances || []).each(&block)
|
39
|
+
end
|
40
|
+
|
41
|
+
def actor_name(event_name)
|
42
|
+
self[event_name].actor
|
43
|
+
end
|
44
|
+
|
45
|
+
def valid_names
|
46
|
+
(@instances || []).map(&:name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def valid_name?(event_name)
|
50
|
+
valid_names.include?(event_name.to_s)
|
51
|
+
end
|
52
|
+
|
53
|
+
def raise_unless_valid_name(event_name)
|
54
|
+
return if valid_name?(event_name)
|
55
|
+
raise UserstampError, "Invalid event name '#{event_name.inspect}'. Event name must be one of #{valid_names.inspect}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Event.create(:create , :creator, 'created_by')
|
61
|
+
Event.create(:update , :updater, 'updated_by', :actual_hook => :before_save)
|
62
|
+
Event.create(:destroy, :deleter, 'deleted_by') #, :after_callback => "save")
|
63
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'userstamp'
|
3
|
+
|
4
|
+
module Userstamp
|
5
|
+
|
6
|
+
module MagicColumns
|
7
|
+
def self.included(mod)
|
8
|
+
mod.extend(ClassMethods)
|
9
|
+
mod.instance_eval do
|
10
|
+
alias :columns_without_userstamp :columns
|
11
|
+
alias :columns :columns_with_userstamp
|
12
|
+
alias :stampable_on_without_magic_columns :stampable_on
|
13
|
+
alias :stampable_on :stampable_on_with_magic_columns
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def ignore_userstamp(value = nil)
|
19
|
+
@ignore_userstamp = value unless value.nil?
|
20
|
+
!!@ignore_userstamp
|
21
|
+
end
|
22
|
+
|
23
|
+
def stampable_on_with_magic_columns(*args, &block)
|
24
|
+
ignore_userstamp(true)
|
25
|
+
stampable_on_without_magic_columns(*args, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def columns_with_userstamp
|
29
|
+
result = columns_without_userstamp
|
30
|
+
unless @ignore_userstamp || @magic_columns_loaded
|
31
|
+
setup_userstamp(result)
|
32
|
+
@magic_columns_loaded = true
|
33
|
+
end
|
34
|
+
result
|
35
|
+
end
|
36
|
+
|
37
|
+
def setup_userstamp(columns)
|
38
|
+
config = Userstamp.config
|
39
|
+
columns.each do |column|
|
40
|
+
next if column.primary
|
41
|
+
if pattern = config.pattern_for(self, column.name)
|
42
|
+
stampable_on(*pattern.args_for_stampable_on(column.name))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'userstamp'
|
2
|
+
|
3
|
+
module Userstamp
|
4
|
+
module MigrationHelper
|
5
|
+
def self.included(base) # :nodoc:
|
6
|
+
base.send(:include, InstanceMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module InstanceMethods
|
10
|
+
def userstamps(include_deleted_by = false)
|
11
|
+
column(Userstamp.compatibility_mode ? :created_by : :creator_id, :integer)
|
12
|
+
column(Userstamp.compatibility_mode ? :updated_by : :updater_id, :integer)
|
13
|
+
column(Userstamp.compatibility_mode ? :deleted_by : :deleter_id, :integer) if include_deleted_by
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|