accessorize 0.0.1
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/LICENSE +20 -0
- data/README.rdoc +72 -0
- data/Rakefile +100 -0
- data/VERSION +1 -0
- data/generators/accessorize/accessorize_generator.rb +9 -0
- data/generators/accessorize/templates/initializer.rb +4 -0
- data/generators/accessorize/templates/migration.rb +25 -0
- data/lib/accessorize.rb +10 -0
- data/lib/accessorize/accessor.rb +4 -0
- data/lib/accessorize/base.rb +48 -0
- data/lib/accessorize/config.rb +8 -0
- data/lib/accessorize/extension.rb +36 -0
- data/rails/init.rb +1 -0
- data/test/accessorize_test.rb +70 -0
- metadata +78 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Jeff Rafter
|
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.rdoc
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
= Accessorize
|
2
|
+
|
3
|
+
Log all data access for your ActiveRecord models
|
4
|
+
|
5
|
+
== How does it work?
|
6
|
+
|
7
|
+
Sometimes you need to keep rigid logs of who created, updated and even accessed
|
8
|
+
the data in your database. Accessorize simplifies the process by allowing you to
|
9
|
+
register observers for your models declaratively in one place. Each ovbserver
|
10
|
+
will save access events to a single table "accessors" which stores the user that
|
11
|
+
is accessing the record, the type of access (create, update, view, destroy) and
|
12
|
+
the id of the record that was accessed.
|
13
|
+
|
14
|
+
== Performance
|
15
|
+
|
16
|
+
Because accessorize record view level access events it can become very slow. You
|
17
|
+
should only enable it for heavily controlled models. For example, if you have an
|
18
|
+
index page that lists all patients in your database in a table, a new access
|
19
|
+
event is created for every row. Think of the children.
|
20
|
+
|
21
|
+
== Make it work
|
22
|
+
|
23
|
+
First you need to install the gem (hosted on Gemcutter):
|
24
|
+
|
25
|
+
sudo gem install accessorize
|
26
|
+
|
27
|
+
Then you need to run the generator in your project:
|
28
|
+
|
29
|
+
/my/cool/rails/app $ accessorize
|
30
|
+
|
31
|
+
Then you need to edit the accessorize.rb file in config/initializers. You can
|
32
|
+
control the automatic accessor and meta methods:
|
33
|
+
|
34
|
+
Accessorize.configure do |config|
|
35
|
+
config.accessor = :current_user # default
|
36
|
+
config.meta = :current_meta # default
|
37
|
+
end
|
38
|
+
|
39
|
+
Accessorize uses these settings when your model is accessed from a controller.
|
40
|
+
When logging the "accessor_id", it will by default grab the id current_user from
|
41
|
+
the application controller. You can change which method is called and replace it
|
42
|
+
with something custom.
|
43
|
+
|
44
|
+
The meta information has no specific use. It could be used to store the users
|
45
|
+
IP address, the current action or route, or really anything you like. Again,
|
46
|
+
accessorize will by default try to access the current_meta method on the
|
47
|
+
application controller. You can define this method or point it to something
|
48
|
+
else. If the method does not exist, the meta attribute will be nil for the
|
49
|
+
record.
|
50
|
+
|
51
|
+
If you are not saving from a controller you can simply set these values to
|
52
|
+
whatever you like:
|
53
|
+
|
54
|
+
Accessorize::Extension.accessor = 101
|
55
|
+
SomeAccessorizedModel.first
|
56
|
+
Accessorize::Accessor.last.accessor
|
57
|
+
# => 101
|
58
|
+
|
59
|
+
|
60
|
+
== Note on Patches/Pull Requests
|
61
|
+
|
62
|
+
* Fork the project.
|
63
|
+
* Make your feature addition or bug fix.
|
64
|
+
* Add tests for it. This is important so I don't break it in a
|
65
|
+
future version unintentionally.
|
66
|
+
* Commit, do not mess with rakefile, version, or history.
|
67
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
68
|
+
* Send me a pull request. Bonus points for topic branches.
|
69
|
+
|
70
|
+
== Copyright
|
71
|
+
|
72
|
+
Copyright (c) 2010 Jeff Rafter. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "accessorize"
|
8
|
+
gem.summary = %Q{Log all data access for your ActiveRecord models}
|
9
|
+
gem.description = %Q{Sometimes you need to keep rigid logs of who created, updated and even accessed the data in your database. Accessorize simplifies the process.}
|
10
|
+
gem.email = "jeff@socialrange.org"
|
11
|
+
gem.homepage = "http://github.com/jeffrafter/accessorize"
|
12
|
+
gem.authors = ["Jeff Rafter"]
|
13
|
+
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
|
+
gem.files = FileList["[A-Z]*", "{generators,lib,rails}/**/*", "test/accessorize_test.rb"]
|
15
|
+
gem.test_files = FileList["test/accessorize_test.rb"]
|
16
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
17
|
+
end
|
18
|
+
Jeweler::GemcutterTasks.new
|
19
|
+
rescue LoadError
|
20
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'rake/testtask'
|
24
|
+
Rake::TestTask.new(:test => ["generator:cleanup", "generator:accessorize"]) do |task|
|
25
|
+
task.libs << "lib" << "test" << "test/rails/test"
|
26
|
+
task.pattern = "test/**/*_test.rb"
|
27
|
+
task.verbose = true
|
28
|
+
end
|
29
|
+
|
30
|
+
namespace :test do
|
31
|
+
Rake::TestTask.new(:database => ["generator:cleanup", "generator:database", "generator:accessorize"]) do |task|
|
32
|
+
task.libs << "lib" << "test"
|
33
|
+
task.pattern = "test/**/*_test.rb"
|
34
|
+
task.verbose = true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
begin
|
39
|
+
require 'rcov/rcovtask'
|
40
|
+
Rcov::RcovTask.new do |test|
|
41
|
+
test.libs << 'test'
|
42
|
+
test.pattern = 'test/**/test_*.rb'
|
43
|
+
test.verbose = true
|
44
|
+
end
|
45
|
+
rescue LoadError
|
46
|
+
task :rcov do
|
47
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
generators = %w(accessorize)
|
52
|
+
|
53
|
+
namespace :generator do
|
54
|
+
desc "Cleans up the test app before running the generator"
|
55
|
+
task :cleanup do
|
56
|
+
FileUtils.rm_rf("test/rails")
|
57
|
+
system "cd test && rails rails"
|
58
|
+
|
59
|
+
# I don't like testing performance!
|
60
|
+
FileUtils.rm_rf("test/rails/test/performance")
|
61
|
+
|
62
|
+
system "echo \"\" >> test/rails/config/environments/test.rb"
|
63
|
+
system "echo \"config.gem 'thoughtbot-shoulda', :lib => 'shoulda'\" >> test/rails/config/environments/test.rb"
|
64
|
+
system "echo \"config.gem 'thoughtbot-factory_girl', :lib => 'factory_girl'\" >> test/rails/config/environments/test.rb"
|
65
|
+
|
66
|
+
# Make a thing
|
67
|
+
system "cd test/rails && ./script/generate scaffold thing name:string mood:string"
|
68
|
+
|
69
|
+
FileUtils.mkdir_p("test/rails/vendor/plugins")
|
70
|
+
accessorize_root = File.expand_path(File.dirname(__FILE__))
|
71
|
+
system("ln -s #{accessorize_root} test/rails/vendor/plugins/accessorize")
|
72
|
+
end
|
73
|
+
|
74
|
+
desc "Prepares the application with an alternate database"
|
75
|
+
task :database do
|
76
|
+
puts "== Configuring the database =================================================="
|
77
|
+
system "cp config/database.yml.sample test/rails/config/database.yml"
|
78
|
+
system "cd test/rails && rake db:migrate:reset"
|
79
|
+
end
|
80
|
+
|
81
|
+
desc "Run the accessorize generator"
|
82
|
+
task :accessorize do
|
83
|
+
system "cd test/rails && ./script/generate accessorize && rake db:migrate db:test:prepare"
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
task :test => :check_dependencies
|
89
|
+
|
90
|
+
task :default => :test
|
91
|
+
|
92
|
+
require 'rake/rdoctask'
|
93
|
+
Rake::RDocTask.new do |rdoc|
|
94
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
95
|
+
|
96
|
+
rdoc.rdoc_dir = 'rdoc'
|
97
|
+
rdoc.title = "accessorize #{version}"
|
98
|
+
rdoc.rdoc_files.include('README*')
|
99
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
100
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class AccessorizeGenerator < Rails::Generator::Base
|
2
|
+
def manifest
|
3
|
+
record do |m|
|
4
|
+
m.migration_template 'migration.rb', File.join('db', 'migrate'), :migration_file_name => 'create_accessors'
|
5
|
+
m.directory File.join('config', 'initializers')
|
6
|
+
m.template 'initializer.rb', File.join('config', 'initializers', 'accessorize.rb')
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class CreateAccessors < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :accessors do |t|
|
4
|
+
t.integer :accessor_id
|
5
|
+
t.integer :reference_id
|
6
|
+
t.string :reference_type
|
7
|
+
t.string :event
|
8
|
+
t.string :tag
|
9
|
+
t.text :meta
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
|
13
|
+
change_table :accessors do |t|
|
14
|
+
t.index [:reference_id, :reference_type]
|
15
|
+
t.index :accessor_id
|
16
|
+
t.index :event
|
17
|
+
t.index :tag
|
18
|
+
t.index :created_at
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.down
|
23
|
+
drop_table :accessors
|
24
|
+
end
|
25
|
+
end
|
data/lib/accessorize.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Accessorize
|
2
|
+
module Base
|
3
|
+
def self.included(base)
|
4
|
+
base.send :extend, ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def accessorize
|
9
|
+
send :include, InstanceMethods
|
10
|
+
has_many :accessors, :class_name => 'Accessorize::Accessor', :foreign_key => :reference_id, :conditions => {:reference_type => self.class_name.tableize}
|
11
|
+
after_create :create_access
|
12
|
+
after_update :update_access
|
13
|
+
after_destroy :destroy_access
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module InstanceMethods
|
18
|
+
def create_access
|
19
|
+
create_accessor('create')
|
20
|
+
end
|
21
|
+
|
22
|
+
def update_access
|
23
|
+
create_accessor('update')
|
24
|
+
end
|
25
|
+
|
26
|
+
def destroy_access
|
27
|
+
create_accessor('destroy')
|
28
|
+
end
|
29
|
+
|
30
|
+
# This method is a performance killer and we are not expecting the base
|
31
|
+
# model to define it. If it is defined, this will replace it. In general
|
32
|
+
# if you want to define an additional after_find, call accessorize, then
|
33
|
+
# alias_method_chain the after_find.
|
34
|
+
def after_find
|
35
|
+
create_accessor('view')
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_accessor(event)
|
39
|
+
accessors.create(:event => event,
|
40
|
+
:reference_type => self.class.name.tableize,
|
41
|
+
:accessor_id => Accessorize::Extension.accessor,
|
42
|
+
:meta => Accessorize::Extension.meta)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
ActiveRecord::Base.send :include, Accessorize::Base
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Accessorize
|
2
|
+
module Extension
|
3
|
+
@@meta = nil
|
4
|
+
@@accessor = nil
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.before_filter :set_extension_points
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.meta
|
11
|
+
@@meta.respond_to?(:call) ? @@meta.call : @@meta
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.accessor
|
15
|
+
@@accessor.respond_to?(:call) ? @@accessor.call : @@accessor
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.meta=(value)
|
19
|
+
@@meta = value
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.accessor=(value)
|
23
|
+
@@accessor = value
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def set_extension_points
|
29
|
+
@@meta = lambda { self.send(Accessorize::Config.meta) rescue nil }
|
30
|
+
@@accessor = lambda { self.send(Accessorize::Config.accessor).id rescue nil }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
ActionController::Base.send :include, Accessorize::Extension
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'accessorize')
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
# Not really sure when to do this :)
|
4
|
+
Thing.accessorize
|
5
|
+
Struct.new("User", :id)
|
6
|
+
|
7
|
+
class ApplicationController < ActionController::Base
|
8
|
+
def current_user
|
9
|
+
Struct::User.new(87)
|
10
|
+
end
|
11
|
+
|
12
|
+
def current_meta
|
13
|
+
"Spilled milk"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class AccessorizeTest < ActiveSupport::TestCase
|
18
|
+
should "create an accessor record when creating a thing" do
|
19
|
+
assert_difference 'Accessorize::Accessor.count', 1 do
|
20
|
+
Thing.create
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
should "create an accessor record when updating a thing" do
|
25
|
+
thing = Thing.create
|
26
|
+
assert_difference 'Accessorize::Accessor.count', 1 do
|
27
|
+
thing.update_attributes(:mood => 'Hasslehoffish')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
should "create an accessor record when destroying a thing" do
|
32
|
+
thing = Thing.create
|
33
|
+
assert_difference 'Accessorize::Accessor.count', 1 do
|
34
|
+
thing.destroy
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
should "create an accessor record when viewing a thing" do
|
39
|
+
thing = Thing.create
|
40
|
+
assert_difference 'Accessorize::Accessor.count', 1 do
|
41
|
+
mood = Thing.last.mood
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
should "set the accessor to the current user" do
|
46
|
+
Accessorize::Extension.accessor = 42
|
47
|
+
thing = Thing.create
|
48
|
+
assert_equal 42, Accessorize::Accessor.last.accessor_id
|
49
|
+
end
|
50
|
+
|
51
|
+
should "set the meta to the current meta" do
|
52
|
+
Accessorize::Extension.meta = "We were in the middle of tea"
|
53
|
+
thing = Thing.create
|
54
|
+
assert_equal "We were in the middle of tea", Accessorize::Accessor.last.meta
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class ThingsControllerTest < ActionController::TestCase
|
59
|
+
test "should set the accessor to the current user" do
|
60
|
+
get :show, :id => things(:one).to_param
|
61
|
+
assert_response :success
|
62
|
+
assert_equal 87, Accessorize::Accessor.last.accessor_id
|
63
|
+
end
|
64
|
+
|
65
|
+
test "should set the meta to the current meta" do
|
66
|
+
get :show, :id => things(:one).to_param
|
67
|
+
assert_response :success
|
68
|
+
assert_equal "Spilled milk", Accessorize::Accessor.last.meta
|
69
|
+
end
|
70
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: accessorize
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jeff Rafter
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-10 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: thoughtbot-shoulda
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
description: Sometimes you need to keep rigid logs of who created, updated and even accessed the data in your database. Accessorize simplifies the process.
|
26
|
+
email: jeff@socialrange.org
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- LICENSE
|
33
|
+
- README.rdoc
|
34
|
+
files:
|
35
|
+
- LICENSE
|
36
|
+
- README.rdoc
|
37
|
+
- Rakefile
|
38
|
+
- VERSION
|
39
|
+
- generators/accessorize/accessorize_generator.rb
|
40
|
+
- generators/accessorize/templates/initializer.rb
|
41
|
+
- generators/accessorize/templates/migration.rb
|
42
|
+
- lib/accessorize.rb
|
43
|
+
- lib/accessorize/accessor.rb
|
44
|
+
- lib/accessorize/base.rb
|
45
|
+
- lib/accessorize/config.rb
|
46
|
+
- lib/accessorize/extension.rb
|
47
|
+
- rails/init.rb
|
48
|
+
- test/accessorize_test.rb
|
49
|
+
has_rdoc: true
|
50
|
+
homepage: http://github.com/jeffrafter/accessorize
|
51
|
+
licenses: []
|
52
|
+
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options:
|
55
|
+
- --charset=UTF-8
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
version:
|
70
|
+
requirements: []
|
71
|
+
|
72
|
+
rubyforge_project:
|
73
|
+
rubygems_version: 1.3.5
|
74
|
+
signing_key:
|
75
|
+
specification_version: 3
|
76
|
+
summary: Log all data access for your ActiveRecord models
|
77
|
+
test_files:
|
78
|
+
- test/accessorize_test.rb
|