action_audit 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f7a69b6b0b1590ea99b587a0d5a377b51164ca32
4
+ data.tar.gz: bcbbea403d691b56aca6b4659eee6c88c6d7081f
5
+ SHA512:
6
+ metadata.gz: c54b20f26179f5a30ac772078f82e959b351542d2c65fec5075cb9c28ded58d51171730417ac8636f42ad75f392190b90c1d3ec0683805daf564248d510eafed
7
+ data.tar.gz: 0b396cd1900045a94fe5e30d9783bff26bdd6e5a25d1f61221cacbd74130244295e6e0e54d313421b3b37a25e478335826b8547e56efd1a3a0144184b497d64a
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1 @@
1
+ 2.1.5
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in action_auditor.gemspec
4
+ gemspec
5
+
6
+ gem 'rspec'
7
+ gem 'pry'
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 d.kirichenko
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,66 @@
1
+ # ActionAuditor
2
+
3
+ Allows to record models changes. It can be ActiveRecord models or any other.
4
+ Observer for ActiveRecord are included, for other models you should write your own code.
5
+ You should also take care where to store this changes.
6
+
7
+ We split all changes into actions. Action can be rails controller action or resque/sidekiq/rake task.
8
+ Every action can have unlimited number af attributes. For controller action it can be current user id, response status and anything else.
9
+
10
+ There are thee main items in action_auditor structure:
11
+
12
+ * ActionObserver
13
+ * ModelsObserver
14
+ * Store
15
+
16
+ We offer some default implementation for each of them, but your are free to write your own.
17
+
18
+ ActionsObserver is a class or module, often mixin. It starts ActionAuditor at the beginning of action and stop at the end.
19
+ No changes will be stored if ActionAuditor isn't started.
20
+ It also stores action attributes related to the action. Action attributes can be stored from any place of code
21
+
22
+ ```ruby
23
+ ActionAudit.add_params(user_id: user.id)
24
+ ```
25
+
26
+ You can use ActionAuditor::Controller for Rails controllers and RescueConcern for resque tasks or write your own.
27
+
28
+ ```ruby
29
+ require 'action_auditor/controller_concern'
30
+ class ApplicationController < ActionController::Base
31
+ include ActionAuditor::ControllerConcern
32
+ end
33
+ ```
34
+
35
+ ModelsObserver observe model changes and trigger ActionAuditor to to store them.
36
+ To observe ActiveRecord changes your should add to config/application.rb
37
+
38
+ ```ruby
39
+ config.after_initialize do
40
+ require 'action_auditor/ar'
41
+ ActionAuditor::Ar.observe [MyModel1, MyModel2]
42
+ end
43
+ ```
44
+
45
+ You can add this code for correct work after code reloading in development into config/environment/development.rb
46
+
47
+ ```ruby
48
+ ActionDispatch::Reloader.to_prepare do
49
+ ActionAuditor::Ar.observe [MyModel1, MyModel2]
50
+ end
51
+ ```
52
+
53
+ You could write you own observer for non-ActiveRecord models.
54
+
55
+ The last part of the system is Store. We provide default store that save data to log file,
56
+ but this gem were invented to store data to Postgres database. We don't privide such
57
+ store becase it depends on how do your want to analize this data. You can set up the store in initializer with
58
+
59
+ ```ruby
60
+ ActionAuditor.store = YourStore.new
61
+ ```
62
+
63
+ If you want to see some info logs from this gem you should also configure the logger
64
+ ```ruby
65
+ ActionAuditor.logger = Rails.logger
66
+ ```
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'action_audit/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "action_audit"
8
+ spec.version = ActionAudit::VERSION
9
+ spec.authors = ["denis.kirichenko"]
10
+ spec.email = ["denis.kirichenko@gmail.com"]
11
+ spec.description = %q{Allows to record models changes}
12
+ spec.summary = %q{Allows to record models changes. It can be ActiveRecord models or any other. Observer for ActiveRecord are included, for other models you should write your own code. You should also take care where to store this changes.}
13
+ spec.homepage = "https://github.com/netDalek/action_audit"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'micromachine', '~> 1.1'
22
+ spec.add_dependency 'activesupport'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.3'
25
+ spec.add_development_dependency 'rake'
26
+ end
@@ -0,0 +1,34 @@
1
+ require "active_support/core_ext/module/delegation.rb"
2
+ require 'micromachine'
3
+
4
+ require "action_audit/version"
5
+ require "action_audit/factory"
6
+ require "action_audit/event_processor"
7
+ require "action_audit/log_store"
8
+
9
+ module ActionAudit
10
+ class << self
11
+ delegate :add_change, :add_params, :with_auditor, to: ActionAudit::Factory
12
+
13
+ def store
14
+ @store ||= LogStore.new
15
+ end
16
+ attr_writer :store
17
+
18
+ attr_accessor :logger
19
+
20
+ def info(message)
21
+ logger.info(message) if logger
22
+ end
23
+
24
+ def error(message)
25
+ return unless logger
26
+ if message.respond_to?(:backtrace)
27
+ bt = Rails.backtrace_cleaner.clean(message.backtrace)
28
+ logger.error("[action_audit] #{message}: #{bt}")
29
+ else
30
+ logger.error("[action_audit] #{message}")
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,44 @@
1
+ module ActionAudit
2
+ module Ar
3
+ class UpdateObserver
4
+ include Singleton
5
+ def after_commit(record)
6
+ changes = record.previous_changes
7
+ if changes.present?
8
+ was = Hash[changes.map{|key, value| [key, value.first]}]
9
+ become = Hash[changes.map{|key, value| [key, value.last]}]
10
+ ActionAudit.add_change(record, was, become)
11
+ end
12
+ rescue Exception => e
13
+ ActionAudit.error(e)
14
+ end
15
+ end
16
+
17
+ class DestroyObserver
18
+ include Singleton
19
+ def after_commit(record)
20
+ ActionAudit.add_change(record, record.attributes, {})
21
+ rescue Exception => e
22
+ ActionAudit.error(e)
23
+ end
24
+ end
25
+
26
+ class CreateObserver
27
+ include Singleton
28
+ def after_commit(record)
29
+ ActionAudit.add_change(record, {}, record.attributes)
30
+ rescue Exception => e
31
+ ActionAudit.error(e)
32
+ end
33
+ end
34
+
35
+ def self.observe(*models)
36
+ models.flatten.each do |e|
37
+ cl = e.to_s.camelize.constantize
38
+ cl.after_commit CreateObserver.instance, on: :create
39
+ cl.after_commit UpdateObserver.instance, on: :update
40
+ cl.after_commit DestroyObserver.instance, on: :destroy
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,25 @@
1
+ require 'active_support/concern'
2
+ require 'ostruct'
3
+
4
+ module ActionAudit::ControllerConcern
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ around_filter :audit
9
+ end
10
+
11
+ def audit
12
+ ActionAudit.info("start audit controller")
13
+ ActionAudit.with_auditor do
14
+ ActionAudit.add_params(params.slice("action", "controller"))
15
+ ActionAudit.add_params(user_id: current_user.id) if current_user
16
+ begin
17
+ yield
18
+ ensure
19
+ ActionAudit.add_params(status: response.status)
20
+ ActionAudit.info("add params audit controller #{response.status}")
21
+ ActionAudit.info("finish audit controller")
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ class ActionAudit::EventProcessor
2
+ delegate :info, to: ActionAudit
3
+
4
+ def initialize(store)
5
+ @store = store
6
+ @params = {}
7
+ end
8
+
9
+ def add_change(entity, was, become)
10
+ info "adding changeset for entity #{entity}"
11
+ changes_state.trigger(:entity_changed)
12
+ @store.save_change(@action_id, entity, was, become)
13
+ end
14
+
15
+ def add_params(params)
16
+ @params.merge!(params)
17
+ changes_state.trigger(:params_added)
18
+ end
19
+
20
+ private
21
+
22
+ def changes_state
23
+ @changes_state ||= MicroMachine.new(:nothing).tap do |m|
24
+ m.when(:entity_changed, :nothing => :changed)
25
+ m.when(:params_added, :changed => :changed)
26
+ m.on(:changed) do
27
+ @action_id = @store.upsert_action(@params, @action_id)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ class ActionAudit::Factory
2
+ class << self
3
+ def current
4
+ Thread.current[:action_auditor]
5
+ end
6
+
7
+ def start
8
+ Thread.current[:action_auditor] = ActionAudit::EventProcessor.new(ActionAudit.store)
9
+ end
10
+
11
+ def flush
12
+ Thread.current[:action_auditor] = nil
13
+ end
14
+
15
+ def with_auditor(params = {})
16
+ start
17
+ add_params(params)
18
+ yield
19
+ ensure
20
+ flush
21
+ end
22
+
23
+ def add_params(*args)
24
+ current.add_params(*args) if current
25
+ end
26
+
27
+ def add_change(*args)
28
+ current.add_change(*args) if current
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ class LogStore
2
+ delegate :info, to: ActionAudit
3
+
4
+ def upsert_action(params, id)
5
+ id ||= SecureRandom.uuid
6
+ info "[action_audit] [#{id}] #{params}"
7
+ id
8
+ end
9
+
10
+ def save_change(action_id, entity, was, become)
11
+ params = {
12
+ entity_id: entity.id,
13
+ entity_type: entity.class.name,
14
+ was: was,
15
+ become: become
16
+ }
17
+ info "[audit_changeset] [#{action_id}] #{params}"
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ module ActionAudit::ResqueConcern
2
+ extend ActiveSupport::Concern
3
+
4
+ module ClassMethods
5
+ def around_perform_auditor(*args)
6
+ logger_info "audit job with args #{args}"
7
+ Auditor.start
8
+ Auditor.add_params(args: args, job_name: self.name)
9
+ yield
10
+ ensure
11
+ Auditor.flush
12
+ end
13
+
14
+ private
15
+
16
+ def logger_info(str)
17
+ Rails.logger.info "[Audit] [#{name}] #{str}"
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,3 @@
1
+ module ActionAudit
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ActionAudit do
4
+ let(:params1) { {a: 1} }
5
+ let(:params2) { {b: 1} }
6
+
7
+ let(:entity) { {b: 1} }
8
+ let(:was) { {c: 1} }
9
+ let(:become) { {d: 1} }
10
+
11
+ let(:store) { spy(:store) }
12
+
13
+ it "saves changes when auditor started" do
14
+ ActionAudit.store = store
15
+ expect(store).to receive(:upsert_action).with(params1, nil).and_return(1)
16
+ expect(store).to receive(:save_change).with(1, entity, was, become)
17
+
18
+ ActionAudit.with_auditor do
19
+ ActionAudit.add_params(params1)
20
+ ActionAudit.add_change(entity, was, become)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ require 'action_audit/controller_concern'
4
+ require 'active_support/core_ext/hash/slice'
5
+
6
+ RSpec.describe ActionAudit::ControllerConcern do
7
+ class TestController
8
+ def self.around_filter(_smth)
9
+ end
10
+
11
+ def response
12
+ OpenStruct.new(status: 200)
13
+ end
14
+
15
+ include ActionAudit::ControllerConcern
16
+ end
17
+
18
+ let(:params) { {"action" => "create", "controller" => "my_controller"} }
19
+ let(:controller) { TestController.new }
20
+ let(:response) { OpenStruct.new(status: 200) }
21
+
22
+ let(:store) { spy(:store) }
23
+
24
+ before do
25
+ ActionAudit.store = store
26
+ expect(store).to receive(:upsert_action).with(params, nil).and_return(1).ordered
27
+ expect(store).to receive(:save_change).with(1, :a, :b, :c)
28
+ expect(store).to receive(:upsert_action).with(params.merge(status: 200), 1).and_return(1).ordered
29
+ end
30
+
31
+ it "store change while controller action" do
32
+ expect(controller).to receive_messages(current_user: nil, params: params, response: response)
33
+ controller.audit do
34
+ ActionAudit.add_change(:a, :b, :c)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ActionAudit::EventProcessor do
4
+ let(:params1) { {a: 1} }
5
+ let(:params2) { {b: 1} }
6
+
7
+ let(:entity) { {b: 1} }
8
+ let(:was) { {c: 1} }
9
+ let(:become) { {d: 1} }
10
+
11
+ let(:store) { spy(:store) }
12
+
13
+ subject { described_class.new(store) }
14
+
15
+ it "doesn't save action without changes" do
16
+ subject.add_params(params1)
17
+ subject.add_params(params2)
18
+ end
19
+
20
+ it "saves action with params after first change" do
21
+ expect(store).to receive(:upsert_action).with(params1.merge(params2), nil).and_return(1)
22
+ expect(store).to receive(:save_change).with(1, entity, was, become)
23
+
24
+ subject.add_params(params1)
25
+ subject.add_params(params2)
26
+ subject.add_change(entity, was, become)
27
+ end
28
+
29
+ it "after change added saves action params every time" do
30
+ expect(store).to receive(:upsert_action).with(params1, nil).ordered.and_return(1)
31
+ expect(store).to receive(:save_change).with(1, entity, was, become).ordered
32
+ expect(store).to receive(:upsert_action).with(params1.merge(params2), 1).ordered.and_return(1)
33
+
34
+ subject.add_params(params1)
35
+ subject.add_change(entity, was, become)
36
+ subject.add_params(params2)
37
+ end
38
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ActionAudit::Factory do
4
+ let(:params1) { {a: 1} }
5
+ let(:params2) { {b: 1} }
6
+
7
+ let(:entity) { {b: 1} }
8
+ let(:was) { {c: 1} }
9
+ let(:become) { {d: 1} }
10
+
11
+ let(:store) { spy(:store) }
12
+
13
+ it "saves changes when auditor started" do
14
+ ActionAudit.store = store
15
+ expect(store).to receive(:upsert_action).with(params1, nil).and_return(1)
16
+ expect(store).to receive(:save_change).with(1, entity, was, become)
17
+
18
+ ActionAudit::Factory.with_auditor do
19
+ described_class.add_params(params1)
20
+ described_class.add_change(entity, was, become)
21
+ end
22
+ end
23
+
24
+ it "doesn't saves changes when auditor doesn't started" do
25
+ described_class.add_params(params1)
26
+ described_class.add_change(entity, was, become)
27
+ end
28
+ end
@@ -0,0 +1,95 @@
1
+ require 'action_audit'
2
+ require 'rspec'
3
+ require "rspec/expectations"
4
+ require 'pry'
5
+ # This file was generated by the `rspec --init` command. Conventionally, all
6
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
7
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
8
+ # file to always be loaded, without a need to explicitly require it in any files.
9
+ #
10
+ # Given that it is always loaded, you are encouraged to keep this file as
11
+ # light-weight as possible. Requiring heavyweight dependencies from this file
12
+ # will add to the boot time of your test suite on EVERY test run, even for an
13
+ # individual file that may not need all of that loaded. Instead, consider making
14
+ # a separate helper file that requires the additional dependencies and performs
15
+ # the additional setup, and require it from the spec files that actually need it.
16
+ #
17
+ # The `.rspec` file also contains a few flags that are not defaults but that
18
+ # users commonly want.
19
+ #
20
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
21
+ RSpec.configure do |config|
22
+ # rspec-expectations config goes here. You can use an alternate
23
+ # assertion/expectation library such as wrong or the stdlib/minitest
24
+ # assertions if you prefer.
25
+ config.expect_with :rspec do |expectations|
26
+ # This option will default to `true` in RSpec 4. It makes the `description`
27
+ # and `failure_message` of custom matchers include text for helper methods
28
+ # defined using `chain`, e.g.:
29
+ # be_bigger_than(2).and_smaller_than(4).description
30
+ # # => "be bigger than 2 and smaller than 4"
31
+ # ...rather than:
32
+ # # => "be bigger than 2"
33
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
34
+ end
35
+
36
+ # rspec-mocks config goes here. You can use an alternate test double
37
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
38
+ config.mock_with :rspec do |mocks|
39
+ # Prevents you from mocking or stubbing a method that does not exist on
40
+ # a real object. This is generally recommended, and will default to
41
+ # `true` in RSpec 4.
42
+ mocks.verify_partial_doubles = true
43
+ end
44
+
45
+ config.order = :random
46
+
47
+ # The settings below are suggested to provide a good initial experience
48
+ # with RSpec, but feel free to customize to your heart's content.
49
+ =begin
50
+ # These two settings work together to allow you to limit a spec run
51
+ # to individual examples or groups you care about by tagging them with
52
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
53
+ # get run.
54
+ config.filter_run :focus
55
+ config.run_all_when_everything_filtered = true
56
+
57
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
58
+ # For more details, see:
59
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
60
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
61
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
62
+ config.disable_monkey_patching!
63
+
64
+ # This setting enables warnings. It's recommended, but in some cases may
65
+ # be too noisy due to issues in dependencies.
66
+ config.warnings = true
67
+
68
+ # Many RSpec users commonly either run the entire suite or an individual
69
+ # file, and it's useful to allow more verbose output when running an
70
+ # individual spec file.
71
+ if config.files_to_run.one?
72
+ # Use the documentation formatter for detailed output,
73
+ # unless a formatter has already been configured
74
+ # (e.g. via a command-line flag).
75
+ config.default_formatter = 'doc'
76
+ end
77
+
78
+ # Print the 10 slowest examples and example groups at the
79
+ # end of the spec run, to help surface which specs are running
80
+ # particularly slow.
81
+ config.profile_examples = 10
82
+
83
+ # Run specs in random order to surface order dependencies. If you find an
84
+ # order dependency and want to debug it, you can fix the order by providing
85
+ # the seed, which is printed after each run.
86
+ # --seed 1234
87
+ # config.order = :random
88
+
89
+ # Seed global randomization in this process using the `--seed` CLI option.
90
+ # Setting this allows you to use `--seed` to deterministically reproduce
91
+ # test failures related to randomization by passing the same `--seed` value
92
+ # as the one that triggered the failure.
93
+ Kernel.srand config.seed
94
+ =end
95
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: action_audit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - denis.kirichenko
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: micromachine
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Allows to record models changes
70
+ email:
71
+ - denis.kirichenko@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".ruby-version"
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - action_audit.gemspec
84
+ - lib/action_audit.rb
85
+ - lib/action_audit/ar.rb
86
+ - lib/action_audit/controller_concern.rb
87
+ - lib/action_audit/event_processor.rb
88
+ - lib/action_audit/factory.rb
89
+ - lib/action_audit/log_store.rb
90
+ - lib/action_audit/resque_concern.rb
91
+ - lib/action_audit/version.rb
92
+ - spec/action_audit_spec.rb
93
+ - spec/controller_spec.rb
94
+ - spec/event_processor_spec.rb
95
+ - spec/factory_spec.rb
96
+ - spec/spec_helper.rb
97
+ homepage: https://github.com/netDalek/action_audit
98
+ licenses:
99
+ - MIT
100
+ metadata: {}
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 2.2.2
118
+ signing_key:
119
+ specification_version: 4
120
+ summary: Allows to record models changes. It can be ActiveRecord models or any other.
121
+ Observer for ActiveRecord are included, for other models you should write your own
122
+ code. You should also take care where to store this changes.
123
+ test_files:
124
+ - spec/action_audit_spec.rb
125
+ - spec/controller_spec.rb
126
+ - spec/event_processor_spec.rb
127
+ - spec/factory_spec.rb
128
+ - spec/spec_helper.rb