magic_userstamp 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/.gitignore +5 -0
  2. data/CHANGELOG +26 -0
  3. data/LICENSE +20 -0
  4. data/README.original +179 -0
  5. data/README.rdoc +64 -0
  6. data/Rakefile +45 -0
  7. data/VERSION +1 -0
  8. data/init.rb +12 -0
  9. data/lib/userstamp/config.rb +119 -0
  10. data/lib/userstamp/controller.rb +43 -0
  11. data/lib/userstamp/event.rb +63 -0
  12. data/lib/userstamp/magic_columns.rb +49 -0
  13. data/lib/userstamp/migration_helper.rb +17 -0
  14. data/lib/userstamp/stampable.rb +147 -0
  15. data/lib/userstamp/stamper.rb +41 -0
  16. data/lib/userstamp.rb +17 -0
  17. data/magic_userstamp.gemspec +124 -0
  18. data/rdoc/classes/Ddb/Controller/Userstamp/InstanceMethods.html +105 -0
  19. data/rdoc/classes/Ddb/Controller/Userstamp.html +125 -0
  20. data/rdoc/classes/Ddb/Controller.html +111 -0
  21. data/rdoc/classes/Ddb/Userstamp/MigrationHelper/InstanceMethods.html +142 -0
  22. data/rdoc/classes/Ddb/Userstamp/MigrationHelper.html +111 -0
  23. data/rdoc/classes/Ddb/Userstamp/Stampable/ClassMethods.html +222 -0
  24. data/rdoc/classes/Ddb/Userstamp/Stampable.html +128 -0
  25. data/rdoc/classes/Ddb/Userstamp/Stamper/ClassMethods.html +142 -0
  26. data/rdoc/classes/Ddb/Userstamp/Stamper/InstanceMethods.html +207 -0
  27. data/rdoc/classes/Ddb/Userstamp/Stamper.html +112 -0
  28. data/rdoc/classes/Ddb/Userstamp.html +121 -0
  29. data/rdoc/created.rid +1 -0
  30. data/rdoc/files/CHANGELOG.html +137 -0
  31. data/rdoc/files/LICENSE.html +129 -0
  32. data/rdoc/files/README.html +341 -0
  33. data/rdoc/files/lib/migration_helper_rb.html +101 -0
  34. data/rdoc/files/lib/stampable_rb.html +101 -0
  35. data/rdoc/files/lib/stamper_rb.html +101 -0
  36. data/rdoc/files/lib/userstamp_rb.html +101 -0
  37. data/rdoc/fr_class_index.html +37 -0
  38. data/rdoc/fr_file_index.html +33 -0
  39. data/rdoc/fr_method_index.html +33 -0
  40. data/rdoc/index.html +24 -0
  41. data/rdoc/rdoc-style.css +208 -0
  42. data/spec/compatibility_stamping_spec.rb +76 -0
  43. data/spec/config_spec.rb +155 -0
  44. data/spec/database.yml +4 -0
  45. data/spec/fixtures/comments.yml +16 -0
  46. data/spec/fixtures/people.yml +11 -0
  47. data/spec/fixtures/posts.yml +9 -0
  48. data/spec/fixtures/users.yml +7 -0
  49. data/spec/magic_column_spec.rb +171 -0
  50. data/spec/posts_controller_spec.rb +41 -0
  51. data/spec/resources/controllers/application_controller.rb +2 -0
  52. data/spec/resources/controllers/posts_controller.rb +26 -0
  53. data/spec/resources/controllers/users_controller.rb +12 -0
  54. data/spec/resources/controllers/userstamp_controller.rb +9 -0
  55. data/spec/resources/models/comment.rb +4 -0
  56. data/spec/resources/models/person.rb +4 -0
  57. data/spec/resources/models/ping.rb +7 -0
  58. data/spec/resources/models/post.rb +4 -0
  59. data/spec/resources/models/user.rb +4 -0
  60. data/spec/schema.rb +56 -0
  61. data/spec/spec.opts +6 -0
  62. data/spec/spec_helper.rb +66 -0
  63. data/spec/stamping_spec.rb +114 -0
  64. data/spec/users_controller_spec.rb +33 -0
  65. metadata +145 -0
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.*~
2
+ *.log
3
+ *.sqlite3
4
+ /coverage
5
+ /pkg
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