simple_audit 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +127 -0
- data/Rakefile +1 -1
- data/TODO +6 -1
- data/lib/simple_audit.rb +1 -1
- data/lib/simple_audit/audit.rb +1 -1
- data/lib/simple_audit/helper.rb +3 -2
- data/lib/simple_audit/simple_audit.rb +58 -56
- data/rails-magazine-article.markdown +112 -0
- data/simple_audit.gemspec +7 -4
- data/test/test_helper.rb +1 -2
- data/test/unit/simple_audit_test.rb +1 -1
- metadata +12 -4
data/README.markdown
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
# simple_audit
|
2
|
+
|
3
|
+
Simple auditing solution for ActiveRecord models. Provides an easy way of creating audit logs for complex model associations.
|
4
|
+
Instead of storing audits for all data aggregated by the audited model, you can specify a serializable representation of the model.
|
5
|
+
|
6
|
+
* a helper method is provided to easily display the audit log
|
7
|
+
* the Audit object provides a #delta method which computes the differences between two audits
|
8
|
+
|
9
|
+
In a nutshell:
|
10
|
+
|
11
|
+
class Booking < ActiveRecord::Base
|
12
|
+
simple_audit do |record|
|
13
|
+
# data to be audited
|
14
|
+
{
|
15
|
+
:price => record.price,
|
16
|
+
:period => record.period,
|
17
|
+
...
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# in your view
|
23
|
+
<%= render_audits(@booking) %>
|
24
|
+
|
25
|
+
# Why ?
|
26
|
+
|
27
|
+
simple_audit is intended as a straightforward auditing solution for complex model associations.
|
28
|
+
In a normalized data structure (which is usually the case when using SQL), a core business model will aggregate data from several associated entities.
|
29
|
+
More often than not in such cases, only the core model is of interest from an auditing point of view.
|
30
|
+
|
31
|
+
So instead of auditing every entity separately, with simple_audit you decide for each audited model what data needs to be audited.
|
32
|
+
This data will be serialized on every model update and the available helper methods will render a clear audit trail.
|
33
|
+
|
34
|
+
![Screenshot of helper result](http://github.com/gtarnovan/simple_audit/raw/master/screenshot.png)
|
35
|
+
|
36
|
+
# Installation & Configuration
|
37
|
+
|
38
|
+
## Rails 2.3.x
|
39
|
+
|
40
|
+
### Gem
|
41
|
+
|
42
|
+
# in your config/environment.rb
|
43
|
+
config.gem 'simple_audit'
|
44
|
+
|
45
|
+
# then install if you don't already have it
|
46
|
+
rake gems:install
|
47
|
+
|
48
|
+
### Plugin
|
49
|
+
|
50
|
+
./script/plugin install http://github.com/gtarnovan/simple_audit
|
51
|
+
|
52
|
+
### Post installation
|
53
|
+
# generate & run migration
|
54
|
+
./script/generate simple_audit_migration
|
55
|
+
rake db:migrate
|
56
|
+
|
57
|
+
## Rails 3
|
58
|
+
# in your Gemfile
|
59
|
+
gem 'simple_audit'
|
60
|
+
|
61
|
+
# then install
|
62
|
+
bundle install
|
63
|
+
|
64
|
+
### Post installation
|
65
|
+
# generate & run migration
|
66
|
+
rails generate simple_audit:migration
|
67
|
+
rake db:migrate
|
68
|
+
|
69
|
+
# Usage
|
70
|
+
|
71
|
+
Audit ActiveRecord models. Somewhere in your (backend) views show the audit logs.
|
72
|
+
|
73
|
+
# in your model
|
74
|
+
# app/models/booking.rb
|
75
|
+
|
76
|
+
class Booking < ActiveRecord::Base
|
77
|
+
simple_audit
|
78
|
+
...
|
79
|
+
end
|
80
|
+
|
81
|
+
# in your view
|
82
|
+
# app/views/bookings/booking.html.erb
|
83
|
+
|
84
|
+
...
|
85
|
+
<%= render_audits(@booking) %>
|
86
|
+
...
|
87
|
+
|
88
|
+
# Assumptions and limitations
|
89
|
+
|
90
|
+
* Your user model is called User and the current user User.current
|
91
|
+
See [sentient_user](http://github.com/bokmann/sentient_user) for more information.
|
92
|
+
|
93
|
+
|
94
|
+
## Customize auditing
|
95
|
+
|
96
|
+
By default after each save, all model's attributes are saved in the audits table.
|
97
|
+
You can customize the data which is saved by supplying a block which will return all relevant data for the audited model.
|
98
|
+
|
99
|
+
# app/models/booking.rb
|
100
|
+
|
101
|
+
class Booking < ActiveRecord::Base
|
102
|
+
simple_audit do |record|
|
103
|
+
{
|
104
|
+
:state => record.state,
|
105
|
+
:price => record.price.format,
|
106
|
+
:period => record.period.to_s,
|
107
|
+
:housing_units => record.housing_units.collect(&:name).join('; '),
|
108
|
+
...
|
109
|
+
}
|
110
|
+
end
|
111
|
+
...
|
112
|
+
end
|
113
|
+
|
114
|
+
You can also customize the attribute of the User model which will be stored in the audit.
|
115
|
+
|
116
|
+
# default is :name
|
117
|
+
simple_audit :username_method => :email
|
118
|
+
|
119
|
+
## Rendering audit trail
|
120
|
+
|
121
|
+
A helper method for displaying a list of audits is provided. It will render a decorated list of the provided audits;
|
122
|
+
only the differences between revisions will be shown, thus making the audit information easily readable.
|
123
|
+
|
124
|
+
![Screenshot of helper result](http://github.com/gtarnovan/simple_audit/raw/master/screenshot.png)
|
125
|
+
|
126
|
+
|
127
|
+
Copyright (c) 2010 [Gabriel Târnovan, Cubus Arts](http://cubus.ro "Cubus Arts"), released under the MIT license
|
data/Rakefile
CHANGED
@@ -45,7 +45,7 @@ begin
|
|
45
45
|
gemspec.email = ["gabriel.tarnovan@cubus.ro", "mihai.tarnovan@cubus.ro"]
|
46
46
|
gemspec.homepage = "http://github.com/gtarnovan/simple_audit"
|
47
47
|
gemspec.authors = ["Gabriel Tarnovan", "Mihai Tarnovan"]
|
48
|
-
gemspec.version = "0.1.
|
48
|
+
gemspec.version = "0.1.1"
|
49
49
|
gemspec.files = gem_files
|
50
50
|
gemspec.test_files = test_files
|
51
51
|
|
data/TODO
CHANGED
@@ -2,11 +2,16 @@
|
|
2
2
|
* support for ActiveModel
|
3
3
|
* ORM agnosticism
|
4
4
|
|
5
|
-
#
|
5
|
+
# Functionality
|
6
6
|
* provide some sort of UUID for audited models that identify these independently from the database provided ID.
|
7
7
|
in case of deletion and creation of a new entity with the same UUID, the audit trails of both entities could be bound.
|
8
8
|
e.g. for an invoice the UUID could be its number/series combination. when someone deletes an invoice and creates a new one
|
9
9
|
with the same UUID, the audit trail of both instances should be bound, such that the deletion event is visible during the audit (i.e. in the view helper)
|
10
10
|
|
11
|
+
* recent activity page
|
12
|
+
|
13
|
+
# Testing
|
14
|
+
* test helper
|
15
|
+
|
11
16
|
# Minor
|
12
17
|
* provide a sample css file for audit trail rendering
|
data/lib/simple_audit.rb
CHANGED
data/lib/simple_audit/audit.rb
CHANGED
data/lib/simple_audit/helper.rb
CHANGED
@@ -14,7 +14,7 @@ module SimpleAudit #:nodoc:
|
|
14
14
|
content_tag(:div, audit.username, :class => "user") +
|
15
15
|
content_tag(:div, l(audit.created_at), :class => "timestamp") +
|
16
16
|
content_tag(:div, :class => 'changes') do
|
17
|
-
if older_audit.present?
|
17
|
+
changes = if older_audit.present?
|
18
18
|
audit.delta(older_audit).collect do |k, v|
|
19
19
|
"\n" +
|
20
20
|
audited_model.class.human_attribute_name(k) +
|
@@ -24,7 +24,8 @@ module SimpleAudit #:nodoc:
|
|
24
24
|
end
|
25
25
|
else
|
26
26
|
audit.change_log.reject{|k, v| v.blank?}.collect {|k, v| "\n#{audited_model.class.human_attribute_name(k)}: #{v}"}
|
27
|
-
end
|
27
|
+
end
|
28
|
+
changes.join
|
28
29
|
end
|
29
30
|
end
|
30
31
|
end
|
@@ -7,67 +7,69 @@
|
|
7
7
|
#
|
8
8
|
# See SimpleAudit::ClassMethods#simple_audit for configuration options
|
9
9
|
|
10
|
-
module SimpleAudit
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
module SimpleAudit
|
11
|
+
|
12
|
+
module Model
|
13
|
+
def self.included(base) #:nodoc:
|
14
|
+
base.send :extend, ClassMethods
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
|
19
|
+
# == Configuration options
|
20
|
+
#
|
21
|
+
# * <tt>username_method => symbol</tt> - Call this method on the current user to get the name
|
22
|
+
#
|
23
|
+
# With no block, all the attributes of the audited model will be logged.
|
24
|
+
#
|
25
|
+
# class Booking
|
26
|
+
# # this is equivalent to passing no block
|
27
|
+
# simple_audit do |audited_record|
|
28
|
+
# audited_record.attributes
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# If a block is given, the data returned by the block will be saved in the audit's change log.
|
33
|
+
#
|
34
|
+
# class Booking
|
35
|
+
# has_many :housing_units
|
36
|
+
# simple_audit do |audited_record|
|
37
|
+
# {
|
38
|
+
# :some_relevant_attribute => audited_record.some_relevant_attribute,
|
39
|
+
# :human_readable_serialization_of_aggregated_models => audited_record.housing_units.collect(&:to_s),
|
40
|
+
# ...
|
41
|
+
# }
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
|
46
|
+
def simple_audit(options = {}, &block)
|
47
|
+
class_eval do
|
14
48
|
|
15
|
-
|
16
|
-
|
17
|
-
# == Configuration options
|
18
|
-
#
|
19
|
-
# * <tt>username_method => symbol</tt> - Call this method on the current user to get the name
|
20
|
-
#
|
21
|
-
# With no block, all the attributes of the audited model will be logged.
|
22
|
-
#
|
23
|
-
# class Booking
|
24
|
-
# # this is equivalent to passing no block
|
25
|
-
# simple_audit do |audited_record|
|
26
|
-
# audited_record.attributes
|
27
|
-
# end
|
28
|
-
# end
|
29
|
-
#
|
30
|
-
# If a block is given, the data returned by the block will be saved in the audit's change log.
|
31
|
-
#
|
32
|
-
# class Booking
|
33
|
-
# has_many :housing_units
|
34
|
-
# simple_audit do |audited_record|
|
35
|
-
# {
|
36
|
-
# :some_relevant_attribute => audited_record.some_relevant_attribute,
|
37
|
-
# :human_readable_serialization_of_aggregated_models => audited_record.housing_units.collect(&:to_s),
|
38
|
-
# ...
|
39
|
-
# }
|
40
|
-
# end
|
41
|
-
# end
|
42
|
-
#
|
49
|
+
write_inheritable_attribute :username_method, (options[:username_method] || :name).to_sym
|
50
|
+
class_inheritable_reader :username_method
|
43
51
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
write_inheritable_attribute :username_method, (options[:username_method] || :name).to_sym
|
48
|
-
class_inheritable_reader :username_method
|
49
|
-
|
50
|
-
audit_changes_proc = block_given? ? block.to_proc : Proc.new {|record| record.attributes}
|
51
|
-
write_inheritable_attribute :audit_changes, audit_changes_proc
|
52
|
-
class_inheritable_reader :audit_changes
|
52
|
+
audit_changes_proc = block_given? ? block.to_proc : Proc.new {|record| record.attributes}
|
53
|
+
write_inheritable_attribute :audit_changes, audit_changes_proc
|
54
|
+
class_inheritable_reader :audit_changes
|
53
55
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
has_many :audits, :as => :auditable, :class_name => '::SimpleAudit::Audit'
|
57
|
+
|
58
|
+
after_create {|record| record.class.audit(record, :create)}
|
59
|
+
after_update {|record| record.class.audit(record, :update)}
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def audit(record, action = :update, user = nil) #:nodoc:
|
65
|
+
user ||= User.current if User.respond_to?(:current)
|
66
|
+
record.audits.create(:user => user,
|
67
|
+
:username => user.try(self.username_method),
|
68
|
+
:action => action.to_s,
|
69
|
+
:change_log => self.audit_changes.call(record)
|
70
|
+
)
|
59
71
|
end
|
60
72
|
end
|
61
73
|
|
62
|
-
def audit(record, action = :update, user = nil) #:nodoc:
|
63
|
-
user ||= User.current if User.respond_to?(:current)
|
64
|
-
record.audits.create(:user => user,
|
65
|
-
:username => user.try(self.username_method),
|
66
|
-
:action => action.to_s,
|
67
|
-
:change_log => self.audit_changes.call(record)
|
68
|
-
)
|
69
|
-
end
|
70
|
-
|
71
74
|
end
|
72
|
-
|
73
75
|
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# Auditing in Rails
|
2
|
+
|
3
|
+
Auditing is a broad term, but when talking about web applications it usually refers to keeping track of who did what, and when. Auditing changes in models is a common requirement for web applications. For Rails there are several solutions which provide this functionality. We'll be looking at two of the best solutions available - acts_as_audit and paper_trail - and introduce simple_audit, a straightforward approach focusing on human readable audit trails.
|
4
|
+
|
5
|
+
## Implementing Auditing with Rails
|
6
|
+
|
7
|
+
Implementing an auditing solution for ActiveRecord models is pretty straightforward due to the many interception points ActiveRecord provides in the lifecycle of a record with callbacks, observers and cache sweepers. Every change to a record can thus easily be tracked and stored in the database.
|
8
|
+
|
9
|
+
<pre>
|
10
|
+
class AuditObserver < ActiveRecord::Observer
|
11
|
+
observe :person, :account
|
12
|
+
|
13
|
+
def after_update(record)
|
14
|
+
AuditTrail.new(record, "UPDATED")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
</pre>
|
18
|
+
|
19
|
+
As you can see, the problem with using observers is that the user who performed the update is not accessible. Sweepers don't have this problem, as they can access the session through the controller, but they will only track changes originating in controller actions. To work around this problem when employing observers/callbacks, many solutions use Thread.local to store the currently logged user, making the data globally available.
|
20
|
+
|
21
|
+
There are two main approaches for storing the audited records' changes:
|
22
|
+
|
23
|
+
* one additional audit table for each audited model; audit tables will have the same structure as the audited tables
|
24
|
+
* a single audit table for all audited models; tracked changes are stored in a serialized form
|
25
|
+
|
26
|
+
Using the first approach allows one to issue database queries directly on the audited attributes of a model; this can not be done efficiently with a serialized form used by the second approach.
|
27
|
+
|
28
|
+
The second approach is used more widely due its flexibility:
|
29
|
+
|
30
|
+
* any number of models can be audited
|
31
|
+
* changes to the attributes of the audited models don't require any updates to the audits table or to the already audited changes
|
32
|
+
* database backups / exports can be managed easier
|
33
|
+
* smaller footprint - only the changed attributes can be stored, not the entire record
|
34
|
+
|
35
|
+
Versioning solutions are very similar to auditing solutions; core functionality is basically the same. This is why versioning systems are sometimes also employed for the auditing system of an application or vice versa. See [vestal_versions](http://github.com/laserlemon/vestal_versions) for a solid versioning solution.
|
36
|
+
|
37
|
+
When relying on ActiveRecord's hooks in the lifecycle of a record to perform auditing, one should keep in mind that some operations will not trigger callbacks and will have to be audited separately. Such operations include direct queries to the database, methods that don't instantiate the records like ActiveRecord#delete_all, #update_all, updating counter caches on associations, etc.
|
38
|
+
|
39
|
+
## Available Auditing Solutions for Rails
|
40
|
+
|
41
|
+
[acts_as_audit](http://github.com/collectiveidea/acts_as_audited) is an established solution for auditing in Rails, having been around since Rails 1.2. It stores each change to a model's attributes in an audit table. The initial value is also stored, making each audit entry self-contained. One can specify which attributes should be audited; the _current_user_ method of the controller is used to get the acting user. A list of versions is available for each audited records.
|
42
|
+
|
43
|
+
[paper_trail](http://github.com/airblade/paper_trail) is a good solution for both auditing and versioning your models. Besides the functionality provided by acts_as_audited, it allows you to store arbitrary controller-level information (e.g. remote IP, user agent, etc) and also arbitrary model-level metadata with each version. Metadata fields must have their respective columns in the audits table; this allows audits to be quickly filtered using SQL rather then deserializing all data and then filtering it.
|
44
|
+
|
45
|
+
## Keeping it simple: simple_audit
|
46
|
+
|
47
|
+
[simple_audit](http://github.com/gtarnovan/simple_audit) is an auditing solution for Rails primarily intended to be used when the human readable representation of the changes is the main reason for implementing the audit. It handles everything from storing record changes to displaying a human readable audit trail.
|
48
|
+
|
49
|
+
Many applications need auditing just to show to a privileged user details about actions performed on the database records. Versioning, storing all changed attributes - especially database internal data like record ids - are not as important as displaying a human readable activity feed in a form that is easy to interpret.
|
50
|
+
|
51
|
+
simple_audit encourages the developer to generate a readable representation of the relevant attributes of a model. This is especially helpful when tracking changes on the parent of a complex aggregation or on a composite record (see [aggregation vs composition](http://en.wikipedia.org/wiki/Object_composition#Aggregation) ).
|
52
|
+
Tracking changes on all records in the database is required in certain situations, but it gets complicated if one has to rebuild an aggregation of several audited records just to display a readable audit log.
|
53
|
+
|
54
|
+
Let's look at an example:
|
55
|
+
|
56
|
+
<pre>
|
57
|
+
class Person < ActiveRecord::Base
|
58
|
+
belongs_to :booking
|
59
|
+
has_one :address
|
60
|
+
end
|
61
|
+
|
62
|
+
class Room < ActiveRecord::Base
|
63
|
+
has_many :room_bookings
|
64
|
+
has_many :bookings, :through => :room_bookings
|
65
|
+
end
|
66
|
+
|
67
|
+
class RoomBooking < ActiveRecord::Base
|
68
|
+
belongs_to :room
|
69
|
+
belongs_to :booking
|
70
|
+
end
|
71
|
+
|
72
|
+
class Booking < ActiveRecord::Base
|
73
|
+
has_one :person
|
74
|
+
has_many :room_bookings
|
75
|
+
has_many :rooms, :through => :room_bookings
|
76
|
+
|
77
|
+
simple_audit do |booking|
|
78
|
+
# this is a human readable representation of the relevant attributes
|
79
|
+
{
|
80
|
+
:person => "#{booking.person.full_name} #{booking.address.to_s}",
|
81
|
+
:housing_units => booking.rooms.collect(&:name).join('; '),
|
82
|
+
:arrival => booking.arrival,
|
83
|
+
...
|
84
|
+
# other relevant data
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
</pre>
|
90
|
+
|
91
|
+
The audit trail generated by the supplied view helper will look like this:
|
92
|
+
|
93
|
+
![Screenshot of helper result](http://github.com/gtarnovan/simple_audit/raw/master/screenshot.png)
|
94
|
+
|
95
|
+
In this context, changes made to booking records are central to the application domain. RoomBooking and Person records are relevant only in the context of a booking, therefore auditing them separately would make little sense and would require recomposing data from several audit entries just to show a single change in a booking.
|
96
|
+
|
97
|
+
simple_audit works on Rails 2.3.x and Rails 3.
|
98
|
+
|
99
|
+
### Future developments of simple_audit
|
100
|
+
|
101
|
+
Support for other ORMs is planned to be implemented until end of november. This will include support for DataMapper and MongoDB.
|
102
|
+
|
103
|
+
Another planned development is auditing controller actions. Not every action results in a change to the database, but even such actions are sometimes worth tracking (e.g. login & logout, searches, sending email, etc).
|
104
|
+
<br />
|
105
|
+
Tracking database updates and controller actions would cover most auditing needs for web applications.
|
106
|
+
|
107
|
+
Integration of [Aquarium](http://aquarium.rubyforge.org/) AOP library to enable auditing of any relevant method call will also be investigated.
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
|
data/simple_audit.gemspec
CHANGED
@@ -5,22 +5,24 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{simple_audit}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Gabriel Tarnovan", "Mihai Tarnovan"]
|
12
|
-
s.date = %q{2010-09
|
12
|
+
s.date = %q{2010-11-09}
|
13
13
|
s.description = %q{ Provides a straightforward way for auditing changes on active record models, especially for composite entities.
|
14
14
|
Also provides helper methods for easily rendering an audit trail in Ruby on Rails views.
|
15
15
|
}
|
16
16
|
s.email = ["gabriel.tarnovan@cubus.ro", "mihai.tarnovan@cubus.ro"]
|
17
17
|
s.extra_rdoc_files = [
|
18
18
|
"LICENSE",
|
19
|
+
"README.markdown",
|
19
20
|
"TODO"
|
20
21
|
]
|
21
22
|
s.files = [
|
22
23
|
"CHANGELOG",
|
23
24
|
"LICENSE",
|
25
|
+
"README.markdown",
|
24
26
|
"Rakefile",
|
25
27
|
"TODO",
|
26
28
|
"generators/simple_audit_migration/USAGE",
|
@@ -32,6 +34,7 @@ Gem::Specification.new do |s|
|
|
32
34
|
"lib/simple_audit/audit.rb",
|
33
35
|
"lib/simple_audit/helper.rb",
|
34
36
|
"lib/simple_audit/simple_audit.rb",
|
37
|
+
"rails-magazine-article.markdown",
|
35
38
|
"rails/init.rb",
|
36
39
|
"screenshot.png",
|
37
40
|
"simple_audit.gemspec",
|
@@ -44,7 +47,7 @@ Gem::Specification.new do |s|
|
|
44
47
|
s.rdoc_options = ["--charset=UTF-8"]
|
45
48
|
s.require_paths = ["lib"]
|
46
49
|
s.rubyforge_project = %q{simple_audit}
|
47
|
-
s.rubygems_version = %q{1.3.
|
50
|
+
s.rubygems_version = %q{1.3.7}
|
48
51
|
s.summary = %q{Simple auditing solution for ActiveRecord models}
|
49
52
|
s.test_files = [
|
50
53
|
"test/fixtures",
|
@@ -59,7 +62,7 @@ Gem::Specification.new do |s|
|
|
59
62
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
60
63
|
s.specification_version = 3
|
61
64
|
|
62
|
-
if Gem::Version.new(Gem::
|
65
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
63
66
|
else
|
64
67
|
end
|
65
68
|
else
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_audit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 25
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Gabriel Tarnovan
|
@@ -15,7 +16,7 @@ autorequire:
|
|
15
16
|
bindir: bin
|
16
17
|
cert_chain: []
|
17
18
|
|
18
|
-
date: 2010-09
|
19
|
+
date: 2010-11-09 00:00:00 +01:00
|
19
20
|
default_executable:
|
20
21
|
dependencies: []
|
21
22
|
|
@@ -29,10 +30,12 @@ extensions: []
|
|
29
30
|
|
30
31
|
extra_rdoc_files:
|
31
32
|
- LICENSE
|
33
|
+
- README.markdown
|
32
34
|
- TODO
|
33
35
|
files:
|
34
36
|
- CHANGELOG
|
35
37
|
- LICENSE
|
38
|
+
- README.markdown
|
36
39
|
- Rakefile
|
37
40
|
- TODO
|
38
41
|
- generators/simple_audit_migration/USAGE
|
@@ -44,6 +47,7 @@ files:
|
|
44
47
|
- lib/simple_audit/audit.rb
|
45
48
|
- lib/simple_audit/helper.rb
|
46
49
|
- lib/simple_audit/simple_audit.rb
|
50
|
+
- rails-magazine-article.markdown
|
47
51
|
- rails/init.rb
|
48
52
|
- screenshot.png
|
49
53
|
- simple_audit.gemspec
|
@@ -61,23 +65,27 @@ rdoc_options:
|
|
61
65
|
require_paths:
|
62
66
|
- lib
|
63
67
|
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
64
69
|
requirements:
|
65
70
|
- - ">="
|
66
71
|
- !ruby/object:Gem::Version
|
72
|
+
hash: 3
|
67
73
|
segments:
|
68
74
|
- 0
|
69
75
|
version: "0"
|
70
76
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
71
78
|
requirements:
|
72
79
|
- - ">="
|
73
80
|
- !ruby/object:Gem::Version
|
81
|
+
hash: 3
|
74
82
|
segments:
|
75
83
|
- 0
|
76
84
|
version: "0"
|
77
85
|
requirements: []
|
78
86
|
|
79
87
|
rubyforge_project: simple_audit
|
80
|
-
rubygems_version: 1.3.
|
88
|
+
rubygems_version: 1.3.7
|
81
89
|
signing_key:
|
82
90
|
specification_version: 3
|
83
91
|
summary: Simple auditing solution for ActiveRecord models
|