velocity_audited 5.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +115 -0
- data/.gitignore +17 -0
- data/.standard.yml +5 -0
- data/.yardopts +3 -0
- data/Appraisals +44 -0
- data/CHANGELOG.md +419 -0
- data/Gemfile +3 -0
- data/LICENSE +19 -0
- data/README.md +433 -0
- data/Rakefile +18 -0
- data/gemfiles/rails50.gemfile +10 -0
- data/gemfiles/rails51.gemfile +10 -0
- data/gemfiles/rails52.gemfile +10 -0
- data/gemfiles/rails60.gemfile +10 -0
- data/gemfiles/rails61.gemfile +10 -0
- data/gemfiles/rails70.gemfile +10 -0
- data/lib/audited/audit.rb +198 -0
- data/lib/audited/auditor.rb +476 -0
- data/lib/audited/railtie.rb +16 -0
- data/lib/audited/rspec_matchers.rb +228 -0
- data/lib/audited/sweeper.rb +67 -0
- data/lib/audited/version.rb +5 -0
- data/lib/audited-rspec.rb +6 -0
- data/lib/audited.rb +49 -0
- data/lib/generators/audited/install_generator.rb +27 -0
- data/lib/generators/audited/migration.rb +17 -0
- data/lib/generators/audited/migration_helper.rb +11 -0
- data/lib/generators/audited/templates/add_association_to_audits.rb +13 -0
- data/lib/generators/audited/templates/add_comment_to_audits.rb +11 -0
- data/lib/generators/audited/templates/add_remote_address_to_audits.rb +12 -0
- data/lib/generators/audited/templates/add_request_uuid_to_audits.rb +12 -0
- data/lib/generators/audited/templates/add_version_to_auditable_index.rb +23 -0
- data/lib/generators/audited/templates/install.rb +32 -0
- data/lib/generators/audited/templates/rename_association_to_associated.rb +25 -0
- data/lib/generators/audited/templates/rename_changes_to_audited_changes.rb +11 -0
- data/lib/generators/audited/templates/rename_parent_to_association.rb +13 -0
- data/lib/generators/audited/templates/revert_polymorphic_indexes_order.rb +22 -0
- data/lib/generators/audited/upgrade_generator.rb +70 -0
- data/lib/velocity_audited.rb +5 -0
- data/spec/audited/audit_spec.rb +357 -0
- data/spec/audited/auditor_spec.rb +1097 -0
- data/spec/audited/rspec_matchers_spec.rb +69 -0
- data/spec/audited/sweeper_spec.rb +133 -0
- data/spec/audited_spec.rb +18 -0
- data/spec/audited_spec_helpers.rb +32 -0
- data/spec/rails_app/app/assets/config/manifest.js +2 -0
- data/spec/rails_app/config/application.rb +13 -0
- data/spec/rails_app/config/database.yml +26 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/test.rb +47 -0
- data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_app/config/initializers/inflections.rb +2 -0
- data/spec/rails_app/config/initializers/secret_token.rb +3 -0
- data/spec/rails_app/config/routes.rb +3 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/active_record/models.rb +151 -0
- data/spec/support/active_record/postgres/1_change_audited_changes_type_to_json.rb +11 -0
- data/spec/support/active_record/postgres/2_change_audited_changes_type_to_jsonb.rb +11 -0
- data/spec/support/active_record/schema.rb +90 -0
- data/test/db/version_1.rb +17 -0
- data/test/db/version_2.rb +18 -0
- data/test/db/version_3.rb +18 -0
- data/test/db/version_4.rb +19 -0
- data/test/db/version_5.rb +17 -0
- data/test/db/version_6.rb +19 -0
- data/test/install_generator_test.rb +62 -0
- data/test/test_helper.rb +18 -0
- data/test/upgrade_generator_test.rb +97 -0
- metadata +260 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Models::ActiveRecord::UserExceptPassword do
|
4
|
+
let(:non_audited_columns) { subject.class.non_audited_columns }
|
5
|
+
|
6
|
+
it { should_not be_audited.only(non_audited_columns) }
|
7
|
+
it { should be_audited.except(:password) }
|
8
|
+
it { should_not be_audited.requires_comment }
|
9
|
+
it { should be_audited.on(:create, :update, :destroy) }
|
10
|
+
# test chaining
|
11
|
+
it { should be_audited.except(:password).on(:create, :update, :destroy) }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe Models::ActiveRecord::UserOnlyPassword do
|
15
|
+
let(:audited_columns) { subject.class.audited_columns }
|
16
|
+
|
17
|
+
it { should be_audited.only(:password) }
|
18
|
+
it { should_not be_audited.except(audited_columns) }
|
19
|
+
it { should_not be_audited.requires_comment }
|
20
|
+
it { should be_audited.on(:create, :update, :destroy) }
|
21
|
+
it { should be_audited.only(:password).on(:create, :update, :destroy) }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe Models::ActiveRecord::CommentRequiredUser do
|
25
|
+
let(:audited_columns) { subject.class.audited_columns }
|
26
|
+
let(:non_audited_columns) { subject.class.non_audited_columns }
|
27
|
+
|
28
|
+
it { should_not be_audited.only(non_audited_columns) }
|
29
|
+
it { should_not be_audited.except(audited_columns) }
|
30
|
+
it { should be_audited.requires_comment }
|
31
|
+
it { should be_audited.on(:create, :update, :destroy) }
|
32
|
+
it { should be_audited.requires_comment.on(:create, :update, :destroy) }
|
33
|
+
end
|
34
|
+
|
35
|
+
describe Models::ActiveRecord::OnCreateCommentRequiredUser do
|
36
|
+
let(:audited_columns) { subject.class.audited_columns }
|
37
|
+
let(:non_audited_columns) { subject.class.non_audited_columns }
|
38
|
+
|
39
|
+
it { should_not be_audited.only(non_audited_columns) }
|
40
|
+
it { should_not be_audited.except(audited_columns) }
|
41
|
+
it { should be_audited.requires_comment }
|
42
|
+
it { should be_audited.on(:create) }
|
43
|
+
it { should_not be_audited.on(:update, :destroy) }
|
44
|
+
it { should be_audited.requires_comment.on(:create) }
|
45
|
+
end
|
46
|
+
|
47
|
+
describe Models::ActiveRecord::OnUpdateCommentRequiredUser do
|
48
|
+
let(:audited_columns) { subject.class.audited_columns }
|
49
|
+
let(:non_audited_columns) { subject.class.non_audited_columns }
|
50
|
+
|
51
|
+
it { should_not be_audited.only(non_audited_columns) }
|
52
|
+
it { should_not be_audited.except(audited_columns) }
|
53
|
+
it { should be_audited.requires_comment }
|
54
|
+
it { should be_audited.on(:update) }
|
55
|
+
it { should_not be_audited.on(:create, :destroy) }
|
56
|
+
it { should be_audited.requires_comment.on(:update) }
|
57
|
+
end
|
58
|
+
|
59
|
+
describe Models::ActiveRecord::OnDestroyCommentRequiredUser do
|
60
|
+
let(:audited_columns) { subject.class.audited_columns }
|
61
|
+
let(:non_audited_columns) { subject.class.non_audited_columns }
|
62
|
+
|
63
|
+
it { should_not be_audited.only(non_audited_columns) }
|
64
|
+
it { should_not be_audited.except(audited_columns) }
|
65
|
+
it { should be_audited.requires_comment }
|
66
|
+
it { should be_audited.on(:destroy) }
|
67
|
+
it { should_not be_audited.on(:create, :update) }
|
68
|
+
it { should be_audited.requires_comment.on(:destroy) }
|
69
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
SingleCov.covered!
|
4
|
+
|
5
|
+
class AuditsController < ActionController::Base
|
6
|
+
before_action :populate_user
|
7
|
+
|
8
|
+
attr_reader :company
|
9
|
+
|
10
|
+
def create
|
11
|
+
@company = Models::ActiveRecord::Company.create
|
12
|
+
head :ok
|
13
|
+
end
|
14
|
+
|
15
|
+
def update
|
16
|
+
current_user.update!(password: "foo")
|
17
|
+
head :ok
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_accessor :current_user
|
23
|
+
attr_accessor :custom_user
|
24
|
+
|
25
|
+
def populate_user
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe AuditsController do
|
30
|
+
include RSpec::Rails::ControllerExampleGroup
|
31
|
+
render_views
|
32
|
+
|
33
|
+
before do
|
34
|
+
Audited::Railtie.initializers.each(&:run)
|
35
|
+
Audited.current_user_method = :current_user
|
36
|
+
end
|
37
|
+
|
38
|
+
let(:user) { create_user }
|
39
|
+
|
40
|
+
describe "POST audit" do
|
41
|
+
it "should audit user" do
|
42
|
+
controller.send(:current_user=, user)
|
43
|
+
expect {
|
44
|
+
post :create
|
45
|
+
}.to change(Audited::Audit, :count)
|
46
|
+
|
47
|
+
expect(controller.company.audits.last.user).to eq(user)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "does not audit when method is not found" do
|
51
|
+
controller.send(:current_user=, user)
|
52
|
+
Audited.current_user_method = :nope
|
53
|
+
expect {
|
54
|
+
post :create
|
55
|
+
}.to change(Audited::Audit, :count)
|
56
|
+
expect(controller.company.audits.last.user).to eq(nil)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should support custom users for sweepers" do
|
60
|
+
controller.send(:custom_user=, user)
|
61
|
+
Audited.current_user_method = :custom_user
|
62
|
+
|
63
|
+
expect {
|
64
|
+
post :create
|
65
|
+
}.to change(Audited::Audit, :count)
|
66
|
+
|
67
|
+
expect(controller.company.audits.last.user).to eq(user)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should record the remote address responsible for the change" do
|
71
|
+
request.env["REMOTE_ADDR"] = "1.2.3.4"
|
72
|
+
controller.send(:current_user=, user)
|
73
|
+
|
74
|
+
post :create
|
75
|
+
|
76
|
+
expect(controller.company.audits.last.remote_address).to eq("1.2.3.4")
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should record a UUID for the web request responsible for the change" do
|
80
|
+
allow_any_instance_of(ActionDispatch::Request).to receive(:uuid).and_return("abc123")
|
81
|
+
controller.send(:current_user=, user)
|
82
|
+
|
83
|
+
post :create
|
84
|
+
|
85
|
+
expect(controller.company.audits.last.request_uuid).to eq("abc123")
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should call current_user after controller callbacks" do
|
89
|
+
expect(controller).to receive(:populate_user) do
|
90
|
+
controller.send(:current_user=, user)
|
91
|
+
end
|
92
|
+
|
93
|
+
expect {
|
94
|
+
post :create
|
95
|
+
}.to change(Audited::Audit, :count)
|
96
|
+
|
97
|
+
expect(controller.company.audits.last.user).to eq(user)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "PUT update" do
|
102
|
+
it "should not save blank audits" do
|
103
|
+
controller.send(:current_user=, user)
|
104
|
+
|
105
|
+
expect {
|
106
|
+
put :update, params: {id: 123}
|
107
|
+
}.to_not change(Audited::Audit, :count)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe Audited::Sweeper do
|
113
|
+
it "should be thread-safe" do
|
114
|
+
instance = Audited::Sweeper.new
|
115
|
+
|
116
|
+
t1 = Thread.new do
|
117
|
+
sleep 0.5
|
118
|
+
instance.controller = "thread1 controller instance"
|
119
|
+
expect(instance.controller).to eq("thread1 controller instance")
|
120
|
+
end
|
121
|
+
|
122
|
+
t2 = Thread.new do
|
123
|
+
instance.controller = "thread2 controller instance"
|
124
|
+
sleep 1
|
125
|
+
expect(instance.controller).to eq("thread2 controller instance")
|
126
|
+
end
|
127
|
+
|
128
|
+
t1.join
|
129
|
+
t2.join
|
130
|
+
|
131
|
+
expect(instance.controller).to be_nil
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Audited do
|
4
|
+
describe "#store" do
|
5
|
+
describe "maintains state of store" do
|
6
|
+
let(:current_user) { "current_user" }
|
7
|
+
before { Audited.store[:current_user] = current_user }
|
8
|
+
|
9
|
+
it "when executed without fibers" do
|
10
|
+
expect(Audited.store[:current_user]).to eq(current_user)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "when executed with Fibers" do
|
14
|
+
Fiber.new { expect(Audited.store[:current_user]).to eq(current_user) }.resume
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module AuditedSpecHelpers
|
2
|
+
def create_user(attrs = {})
|
3
|
+
Models::ActiveRecord::User.create({name: "Brandon", username: "brandon", password: "password", favourite_device: "Android Phone"}.merge(attrs))
|
4
|
+
end
|
5
|
+
|
6
|
+
def build_user(attrs = {})
|
7
|
+
Models::ActiveRecord::User.new({name: "darth", username: "darth", password: "noooooooo"}.merge(attrs))
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_versions(n = 2, attrs = {})
|
11
|
+
Models::ActiveRecord::User.create(name: "Foobar 1", **attrs).tap do |u|
|
12
|
+
(n - 1).times do |i|
|
13
|
+
u.update_attribute :name, "Foobar #{i + 2}"
|
14
|
+
end
|
15
|
+
u.reload
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def run_migrations(direction, migrations_paths, target_version = nil)
|
20
|
+
if rails_below?("5.2.0.rc1")
|
21
|
+
ActiveRecord::Migrator.send(direction, migrations_paths, target_version)
|
22
|
+
elsif rails_below?("6.0.0.rc1")
|
23
|
+
ActiveRecord::MigrationContext.new(migrations_paths).send(direction, target_version)
|
24
|
+
else
|
25
|
+
ActiveRecord::MigrationContext.new(migrations_paths, ActiveRecord::SchemaMigration).send(direction, target_version)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def rails_below?(rails_version)
|
30
|
+
Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new(rails_version)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "active_record/railtie"
|
2
|
+
|
3
|
+
module RailsApp
|
4
|
+
class Application < Rails::Application
|
5
|
+
config.root = File.expand_path("../../", __FILE__)
|
6
|
+
config.i18n.enforce_available_locales = true
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
require "active_record/connection_adapters/sqlite3_adapter"
|
11
|
+
if ActiveRecord::ConnectionAdapters::SQLite3Adapter.respond_to?(:represent_boolean_as_integer)
|
12
|
+
ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer = true
|
13
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
sqlite3mem: &SQLITE3MEM
|
2
|
+
adapter: sqlite3
|
3
|
+
database: ":memory:"
|
4
|
+
|
5
|
+
sqlite3: &SQLITE
|
6
|
+
adapter: sqlite3
|
7
|
+
database: audited_test.sqlite3.db
|
8
|
+
|
9
|
+
postgresql: &POSTGRES
|
10
|
+
adapter: postgresql
|
11
|
+
username: postgres
|
12
|
+
password: postgres
|
13
|
+
host: localhost
|
14
|
+
database: audited_test
|
15
|
+
min_messages: ERROR
|
16
|
+
|
17
|
+
mysql: &MYSQL
|
18
|
+
adapter: mysql2
|
19
|
+
host: localhost
|
20
|
+
username: root
|
21
|
+
password: root
|
22
|
+
database: audited_test
|
23
|
+
charset: utf8
|
24
|
+
|
25
|
+
test:
|
26
|
+
<<: *<%= ENV['DB'] || 'SQLITE3MEM' %>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
RailsApp::Application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb.
|
3
|
+
|
4
|
+
# The test environment is used exclusively to run your application's
|
5
|
+
# test suite. You never need to work with it otherwise. Remember that
|
6
|
+
# your test database is "scratch space" for the test suite and is wiped
|
7
|
+
# and recreated between test runs. Don't rely on the data there!
|
8
|
+
config.cache_classes = true
|
9
|
+
|
10
|
+
# Do not eager load code on boot. This avoids loading your whole application
|
11
|
+
# just for the purpose of running a single test. If you are using a tool that
|
12
|
+
# preloads Rails for running tests, you may have to set it to true.
|
13
|
+
config.eager_load = false
|
14
|
+
|
15
|
+
# Configure static file server for tests with Cache-Control for performance.
|
16
|
+
if config.respond_to?(:public_file_server)
|
17
|
+
config.public_file_server.enabled = true
|
18
|
+
config.public_file_server.headers = {"Cache-Control" => "public, max-age=3600"}
|
19
|
+
else
|
20
|
+
config.static_cache_control = "public, max-age=3600"
|
21
|
+
config.serve_static_files = true
|
22
|
+
end
|
23
|
+
|
24
|
+
# Show full error reports and disable caching.
|
25
|
+
config.consider_all_requests_local = true
|
26
|
+
# config.action_controller.perform_caching = false
|
27
|
+
|
28
|
+
# Raise exceptions instead of rendering exception templates.
|
29
|
+
config.action_dispatch.show_exceptions = false
|
30
|
+
|
31
|
+
# Disable request forgery protection in test environment.
|
32
|
+
# config.action_controller.allow_forgery_protection = false
|
33
|
+
|
34
|
+
# Tell Action Mailer not to deliver emails to the real world.
|
35
|
+
# The :test delivery method accumulates sent emails in the
|
36
|
+
# ActionMailer::Base.deliveries array.
|
37
|
+
# config.action_mailer.delivery_method = :test
|
38
|
+
|
39
|
+
# Randomize the order test cases are executed.
|
40
|
+
config.active_support.test_order = :random
|
41
|
+
|
42
|
+
# Print deprecation notices to the stderr.
|
43
|
+
config.active_support.deprecation = :stderr
|
44
|
+
|
45
|
+
# Raises error for missing translations
|
46
|
+
# config.action_view.raise_on_missing_translations = true
|
47
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
|
4
|
+
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
|
5
|
+
|
6
|
+
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
|
7
|
+
Rails.backtrace_cleaner.remove_silencers!
|
@@ -0,0 +1,3 @@
|
|
1
|
+
Rails.application.config.secret_token = "ea942c41850d502f2c8283e26bdc57829f471bb18224ddff0a192c4f32cdf6cb5aa0d82b3a7a7adbeb640c4b06f3aa1cd5f098162d8240f669b39d6b49680571"
|
2
|
+
Rails.application.config.session_store :cookie_store, key: "_my_app"
|
3
|
+
Rails.application.config.secret_key_base = "secret value"
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
ENV["RAILS_ENV"] = "test"
|
2
|
+
require "bundler/setup"
|
3
|
+
require "single_cov"
|
4
|
+
SingleCov.setup :rspec
|
5
|
+
|
6
|
+
if Bundler.definition.dependencies.map(&:name).include?("protected_attributes")
|
7
|
+
require "protected_attributes"
|
8
|
+
end
|
9
|
+
require "rails_app/config/environment"
|
10
|
+
require "rspec/rails"
|
11
|
+
require "audited"
|
12
|
+
require "audited-rspec"
|
13
|
+
require "audited_spec_helpers"
|
14
|
+
require "support/active_record/models"
|
15
|
+
|
16
|
+
SPEC_ROOT = Pathname.new(File.expand_path("../", __FILE__))
|
17
|
+
|
18
|
+
Dir[SPEC_ROOT.join("support/*.rb")].sort.each { |f| require f }
|
19
|
+
|
20
|
+
RSpec.configure do |config|
|
21
|
+
config.include AuditedSpecHelpers
|
22
|
+
config.use_transactional_fixtures = false if Rails.version.start_with?("4.")
|
23
|
+
config.use_transactional_tests = false if config.respond_to?(:use_transactional_tests=)
|
24
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require "cgi"
|
2
|
+
require File.expand_path("../schema", __FILE__)
|
3
|
+
|
4
|
+
module Models
|
5
|
+
module ActiveRecord
|
6
|
+
class User < ::ActiveRecord::Base
|
7
|
+
audited except: :password
|
8
|
+
attribute :non_column_attr if Rails.version >= "5.1"
|
9
|
+
attr_protected :logins if respond_to?(:attr_protected)
|
10
|
+
enum status: {active: 0, reliable: 1, banned: 2}
|
11
|
+
serialize :phone_numbers, Array
|
12
|
+
|
13
|
+
def name=(val)
|
14
|
+
write_attribute(:name, CGI.escapeHTML(val))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class UserExceptPassword < ::ActiveRecord::Base
|
19
|
+
self.table_name = :users
|
20
|
+
audited except: :password
|
21
|
+
end
|
22
|
+
|
23
|
+
class UserOnlyPassword < ::ActiveRecord::Base
|
24
|
+
self.table_name = :users
|
25
|
+
attribute :non_column_attr if Rails.version >= "5.1"
|
26
|
+
audited only: :password
|
27
|
+
end
|
28
|
+
|
29
|
+
class UserRedactedPassword < ::ActiveRecord::Base
|
30
|
+
self.table_name = :users
|
31
|
+
audited redacted: :password
|
32
|
+
end
|
33
|
+
|
34
|
+
class UserMultipleRedactedAttributes < ::ActiveRecord::Base
|
35
|
+
self.table_name = :users
|
36
|
+
audited redacted: [:password, :ssn]
|
37
|
+
end
|
38
|
+
|
39
|
+
class UserRedactedPasswordCustomRedaction < ::ActiveRecord::Base
|
40
|
+
self.table_name = :users
|
41
|
+
audited redacted: :password, redaction_value: ["My", "Custom", "Value", 7]
|
42
|
+
end
|
43
|
+
|
44
|
+
class CommentRequiredUser < ::ActiveRecord::Base
|
45
|
+
self.table_name = :users
|
46
|
+
audited except: :password, comment_required: true
|
47
|
+
end
|
48
|
+
|
49
|
+
class OnCreateCommentRequiredUser < ::ActiveRecord::Base
|
50
|
+
self.table_name = :users
|
51
|
+
audited comment_required: true, on: :create
|
52
|
+
end
|
53
|
+
|
54
|
+
class OnUpdateCommentRequiredUser < ::ActiveRecord::Base
|
55
|
+
self.table_name = :users
|
56
|
+
audited comment_required: true, on: :update
|
57
|
+
end
|
58
|
+
|
59
|
+
class OnDestroyCommentRequiredUser < ::ActiveRecord::Base
|
60
|
+
self.table_name = :users
|
61
|
+
audited comment_required: true, on: :destroy
|
62
|
+
end
|
63
|
+
|
64
|
+
class NoUpdateWithCommentOnlyUser < ::ActiveRecord::Base
|
65
|
+
self.table_name = :users
|
66
|
+
audited update_with_comment_only: false
|
67
|
+
end
|
68
|
+
|
69
|
+
class AccessibleAfterDeclarationUser < ::ActiveRecord::Base
|
70
|
+
self.table_name = :users
|
71
|
+
audited
|
72
|
+
attr_accessible :name, :username, :password if respond_to?(:attr_accessible)
|
73
|
+
end
|
74
|
+
|
75
|
+
class AccessibleBeforeDeclarationUser < ::ActiveRecord::Base
|
76
|
+
self.table_name = :users
|
77
|
+
attr_accessible :name, :username, :password if respond_to?(:attr_accessible) # declare attr_accessible before calling aaa
|
78
|
+
audited
|
79
|
+
end
|
80
|
+
|
81
|
+
class NoAttributeProtectionUser < ::ActiveRecord::Base
|
82
|
+
self.table_name = :users
|
83
|
+
audited
|
84
|
+
end
|
85
|
+
|
86
|
+
class UserWithAfterAudit < ::ActiveRecord::Base
|
87
|
+
self.table_name = :users
|
88
|
+
audited
|
89
|
+
attr_accessor :bogus_attr, :around_attr
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def after_audit
|
94
|
+
self.bogus_attr = "do something"
|
95
|
+
end
|
96
|
+
|
97
|
+
def around_audit
|
98
|
+
self.around_attr = yield
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class MaxAuditsUser < ::ActiveRecord::Base
|
103
|
+
self.table_name = :users
|
104
|
+
audited max_audits: 5
|
105
|
+
end
|
106
|
+
|
107
|
+
class Company < ::ActiveRecord::Base
|
108
|
+
audited
|
109
|
+
end
|
110
|
+
|
111
|
+
class Company::STICompany < Company
|
112
|
+
end
|
113
|
+
|
114
|
+
class Owner < ::ActiveRecord::Base
|
115
|
+
self.table_name = "users"
|
116
|
+
audited
|
117
|
+
has_associated_audits
|
118
|
+
has_many :companies, class_name: "OwnedCompany", dependent: :destroy
|
119
|
+
end
|
120
|
+
|
121
|
+
class OwnedCompany < ::ActiveRecord::Base
|
122
|
+
self.table_name = "companies"
|
123
|
+
belongs_to :owner, class_name: "Owner"
|
124
|
+
attr_accessible :name, :owner if respond_to?(:attr_accessible) # declare attr_accessible before calling aaa
|
125
|
+
audited associated_with: :owner
|
126
|
+
end
|
127
|
+
|
128
|
+
class OwnedCompany::STICompany < OwnedCompany
|
129
|
+
end
|
130
|
+
|
131
|
+
class OnUpdateDestroy < ::ActiveRecord::Base
|
132
|
+
self.table_name = "companies"
|
133
|
+
audited on: [:update, :destroy]
|
134
|
+
end
|
135
|
+
|
136
|
+
class OnCreateDestroy < ::ActiveRecord::Base
|
137
|
+
self.table_name = "companies"
|
138
|
+
audited on: [:create, :destroy]
|
139
|
+
end
|
140
|
+
|
141
|
+
class OnCreateDestroyExceptName < ::ActiveRecord::Base
|
142
|
+
self.table_name = "companies"
|
143
|
+
audited except: :name, on: [:create, :destroy]
|
144
|
+
end
|
145
|
+
|
146
|
+
class OnCreateUpdate < ::ActiveRecord::Base
|
147
|
+
self.table_name = "companies"
|
148
|
+
audited on: [:create, :update]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class ChangeAuditedChangesTypeToJson < ActiveRecord::Migration[5.0]
|
2
|
+
def self.up
|
3
|
+
remove_column :audits, :audited_changes
|
4
|
+
add_column :audits, :audited_changes, :json
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.down
|
8
|
+
remove_column :audits, :audited_changes
|
9
|
+
add_column :audits, :audited_changes, :text
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class ChangeAuditedChangesTypeToJsonb < ActiveRecord::Migration[5.0]
|
2
|
+
def self.up
|
3
|
+
remove_column :audits, :audited_changes
|
4
|
+
add_column :audits, :audited_changes, :jsonb
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.down
|
8
|
+
remove_column :audits, :audited_changes
|
9
|
+
add_column :audits, :audited_changes, :text
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require "active_record"
|
2
|
+
require "logger"
|
3
|
+
|
4
|
+
begin
|
5
|
+
if ActiveRecord.version >= Gem::Version.new("6.1.0")
|
6
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first
|
7
|
+
ActiveRecord::Tasks::DatabaseTasks.create(db_config)
|
8
|
+
else
|
9
|
+
db_config = ActiveRecord::Base.configurations[Rails.env].clone
|
10
|
+
db_type = db_config["adapter"]
|
11
|
+
db_name = db_config.delete("database")
|
12
|
+
raise StandardError.new("No database name specified.") if db_name.blank?
|
13
|
+
if db_type == "sqlite3"
|
14
|
+
db_file = Pathname.new(__FILE__).dirname.join(db_name)
|
15
|
+
db_file.unlink if db_file.file?
|
16
|
+
else
|
17
|
+
if defined?(JRUBY_VERSION)
|
18
|
+
db_config.symbolize_keys!
|
19
|
+
db_config[:configure_connection] = false
|
20
|
+
end
|
21
|
+
adapter = ActiveRecord::Base.send("#{db_type}_connection", db_config)
|
22
|
+
adapter.recreate_database db_name, db_config.slice("charset").symbolize_keys
|
23
|
+
adapter.disconnect!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
rescue => e
|
27
|
+
Kernel.warn e
|
28
|
+
end
|
29
|
+
|
30
|
+
logfile = Pathname.new(__FILE__).dirname.join("debug.log")
|
31
|
+
logfile.unlink if logfile.file?
|
32
|
+
ActiveRecord::Base.logger = Logger.new(logfile)
|
33
|
+
|
34
|
+
ActiveRecord::Migration.verbose = false
|
35
|
+
ActiveRecord::Base.establish_connection
|
36
|
+
|
37
|
+
ActiveRecord::Schema.define do
|
38
|
+
create_table :users do |t|
|
39
|
+
t.column :name, :string
|
40
|
+
t.column :username, :string
|
41
|
+
t.column :password, :string
|
42
|
+
t.column :activated, :boolean
|
43
|
+
t.column :status, :integer, default: 0
|
44
|
+
t.column :suspended_at, :datetime
|
45
|
+
t.column :logins, :integer, default: 0
|
46
|
+
t.column :created_at, :datetime
|
47
|
+
t.column :updated_at, :datetime
|
48
|
+
t.column :favourite_device, :string
|
49
|
+
t.column :ssn, :integer
|
50
|
+
t.column :phone_numbers, :string
|
51
|
+
end
|
52
|
+
|
53
|
+
create_table :companies do |t|
|
54
|
+
t.column :name, :string
|
55
|
+
t.column :owner_id, :integer
|
56
|
+
t.column :type, :string
|
57
|
+
end
|
58
|
+
|
59
|
+
create_table :authors do |t|
|
60
|
+
t.column :name, :string
|
61
|
+
end
|
62
|
+
|
63
|
+
create_table :books do |t|
|
64
|
+
t.column :authord_id, :integer
|
65
|
+
t.column :title, :string
|
66
|
+
end
|
67
|
+
|
68
|
+
create_table :audits do |t|
|
69
|
+
t.column :auditable_id, :integer
|
70
|
+
t.column :auditable_type, :string
|
71
|
+
t.column :associated_id, :integer
|
72
|
+
t.column :associated_type, :string
|
73
|
+
t.column :user_id, :integer
|
74
|
+
t.column :user_type, :string
|
75
|
+
t.column :username, :string
|
76
|
+
t.column :action, :string
|
77
|
+
t.column :audited_changes, :text
|
78
|
+
t.column :version, :integer, default: 0
|
79
|
+
t.column :comment, :string
|
80
|
+
t.column :remote_address, :string
|
81
|
+
t.column :request_uuid, :string
|
82
|
+
t.column :created_at, :datetime
|
83
|
+
end
|
84
|
+
|
85
|
+
add_index :audits, [:auditable_id, :auditable_type], name: "auditable_index"
|
86
|
+
add_index :audits, [:associated_id, :associated_type], name: "associated_index"
|
87
|
+
add_index :audits, [:user_id, :user_type], name: "user_index"
|
88
|
+
add_index :audits, :request_uuid
|
89
|
+
add_index :audits, :created_at
|
90
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
ActiveRecord::Schema.define do
|
2
|
+
create_table :audits, force: true do |t|
|
3
|
+
t.column :auditable_id, :integer
|
4
|
+
t.column :auditable_type, :string
|
5
|
+
t.column :user_id, :integer
|
6
|
+
t.column :user_type, :string
|
7
|
+
t.column :username, :string
|
8
|
+
t.column :action, :string
|
9
|
+
t.column :changes, :text
|
10
|
+
t.column :version, :integer, default: 0
|
11
|
+
t.column :created_at, :datetime
|
12
|
+
end
|
13
|
+
|
14
|
+
add_index :audits, [:auditable_id, :auditable_type], name: "auditable_index"
|
15
|
+
add_index :audits, [:user_id, :user_type], name: "user_index"
|
16
|
+
add_index :audits, :created_at
|
17
|
+
end
|