audited-hp 4.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +32 -0
- data/.yardopts +3 -0
- data/Appraisals +22 -0
- data/CHANGELOG +153 -0
- data/Gemfile +3 -0
- data/LICENSE +19 -0
- data/README.md +299 -0
- data/Rakefile +18 -0
- data/gemfiles/rails40.gemfile +9 -0
- data/gemfiles/rails41.gemfile +8 -0
- data/gemfiles/rails42.gemfile +8 -0
- data/gemfiles/rails50.gemfile +8 -0
- data/lib/audited-rspec.rb +4 -0
- data/lib/audited.rb +29 -0
- data/lib/audited/audit.rb +149 -0
- data/lib/audited/auditor.rb +309 -0
- data/lib/audited/rspec_matchers.rb +177 -0
- data/lib/audited/sweeper.rb +60 -0
- data/lib/audited/version.rb +3 -0
- data/lib/generators/audited/install_generator.rb +20 -0
- data/lib/generators/audited/migration.rb +15 -0
- data/lib/generators/audited/templates/add_association_to_audits.rb +11 -0
- data/lib/generators/audited/templates/add_comment_to_audits.rb +9 -0
- data/lib/generators/audited/templates/add_remote_address_to_audits.rb +10 -0
- data/lib/generators/audited/templates/add_request_uuid_to_audits.rb +10 -0
- data/lib/generators/audited/templates/install.rb +30 -0
- data/lib/generators/audited/templates/rename_association_to_associated.rb +23 -0
- data/lib/generators/audited/templates/rename_changes_to_audited_changes.rb +9 -0
- data/lib/generators/audited/templates/rename_parent_to_association.rb +11 -0
- data/lib/generators/audited/upgrade_generator.rb +57 -0
- data/spec/audited/audit_spec.rb +199 -0
- data/spec/audited/auditor_spec.rb +607 -0
- data/spec/audited/sweeper_spec.rb +106 -0
- data/spec/audited_spec_helpers.rb +20 -0
- data/spec/rails_app/config/application.rb +8 -0
- data/spec/rails_app/config/database.yml +24 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/development.rb +21 -0
- data/spec/rails_app/config/environments/production.rb +35 -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 +21 -0
- data/spec/support/active_record/models.rb +99 -0
- data/spec/support/active_record/schema.rb +81 -0
- data/test/db/version_1.rb +17 -0
- data/test/db/version_2.rb +18 -0
- data/test/db/version_3.rb +19 -0
- data/test/db/version_4.rb +20 -0
- data/test/db/version_5.rb +18 -0
- data/test/db/version_6.rb +17 -0
- data/test/install_generator_test.rb +17 -0
- data/test/test_helper.rb +19 -0
- data/test/upgrade_generator_test.rb +77 -0
- metadata +229 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
class AuditsController < ActionController::Base
|
4
|
+
attr_reader :company
|
5
|
+
|
6
|
+
def create
|
7
|
+
@company = Models::ActiveRecord::Company.create
|
8
|
+
head :ok
|
9
|
+
end
|
10
|
+
|
11
|
+
def update
|
12
|
+
current_user.update_attributes(password: 'foo')
|
13
|
+
head :ok
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_accessor :current_user
|
19
|
+
attr_accessor :custom_user
|
20
|
+
end
|
21
|
+
|
22
|
+
describe AuditsController do
|
23
|
+
include RSpec::Rails::ControllerExampleGroup
|
24
|
+
render_views
|
25
|
+
|
26
|
+
before(:each) do
|
27
|
+
Audited.current_user_method = :current_user
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:user) { create_user }
|
31
|
+
|
32
|
+
describe "POST audit" do
|
33
|
+
|
34
|
+
it "should audit user" do
|
35
|
+
controller.send(:current_user=, user)
|
36
|
+
expect {
|
37
|
+
post :create
|
38
|
+
}.to change( Audited::Audit, :count )
|
39
|
+
|
40
|
+
expect(controller.company.audits.last.user).to eq(user)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should support custom users for sweepers" do
|
44
|
+
controller.send(:custom_user=, user)
|
45
|
+
Audited.current_user_method = :custom_user
|
46
|
+
|
47
|
+
expect {
|
48
|
+
post :create
|
49
|
+
}.to change( Audited::Audit, :count )
|
50
|
+
|
51
|
+
expect(controller.company.audits.last.user).to eq(user)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should record the remote address responsible for the change" do
|
55
|
+
request.env['REMOTE_ADDR'] = "1.2.3.4"
|
56
|
+
controller.send(:current_user=, user)
|
57
|
+
|
58
|
+
post :create
|
59
|
+
|
60
|
+
expect(controller.company.audits.last.remote_address).to eq('1.2.3.4')
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should record a UUID for the web request responsible for the change" do
|
64
|
+
allow_any_instance_of(ActionDispatch::Request).to receive(:uuid).and_return("abc123")
|
65
|
+
controller.send(:current_user=, user)
|
66
|
+
|
67
|
+
post :create
|
68
|
+
|
69
|
+
expect(controller.company.audits.last.request_uuid).to eq("abc123")
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "PUT update" do
|
75
|
+
it "should not save blank audits" do
|
76
|
+
controller.send(:current_user=, user)
|
77
|
+
|
78
|
+
expect {
|
79
|
+
put :update, id: 123
|
80
|
+
}.to_not change( Audited::Audit, :count )
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
describe Audited::Sweeper do
|
87
|
+
|
88
|
+
it "should be thread-safe" do
|
89
|
+
t1 = Thread.new do
|
90
|
+
sleep 0.5
|
91
|
+
Audited::Sweeper.instance.controller = 'thread1 controller instance'
|
92
|
+
expect(Audited::Sweeper.instance.controller).to eq('thread1 controller instance')
|
93
|
+
end
|
94
|
+
|
95
|
+
t2 = Thread.new do
|
96
|
+
Audited::Sweeper.instance.controller = 'thread2 controller instance'
|
97
|
+
sleep 1
|
98
|
+
expect(Audited::Sweeper.instance.controller).to eq('thread2 controller instance')
|
99
|
+
end
|
100
|
+
|
101
|
+
t1.join; t2.join
|
102
|
+
|
103
|
+
expect(Audited::Sweeper.instance.controller).to be_nil
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module AuditedSpecHelpers
|
2
|
+
|
3
|
+
def create_user(attrs = {})
|
4
|
+
Models::ActiveRecord::User.create({name: 'Brandon', username: 'brandon', password: 'password'}.merge(attrs))
|
5
|
+
end
|
6
|
+
|
7
|
+
def build_user(attrs = {})
|
8
|
+
Models::ActiveRecord::User.new({name: 'darth', username: 'darth', password: 'noooooooo'}.merge(attrs))
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_versions(n = 2)
|
12
|
+
Models::ActiveRecord::User.create(name: 'Foobar 1').tap do |u|
|
13
|
+
(n - 1).times do |i|
|
14
|
+
u.update_attribute :name, "Foobar #{i + 2}"
|
15
|
+
end
|
16
|
+
u.reload
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
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:
|
13
|
+
database: audited_test
|
14
|
+
min_messages: ERROR
|
15
|
+
|
16
|
+
mysql: &MYSQL
|
17
|
+
adapter: mysql2
|
18
|
+
host: localhost
|
19
|
+
username: root
|
20
|
+
password:
|
21
|
+
database: audited_test
|
22
|
+
|
23
|
+
test:
|
24
|
+
<<: *<%= ENV['DB'] || 'SQLITE3MEM' %>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
RailsApp::Application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/environment.rb
|
3
|
+
|
4
|
+
# In the development environment your application's code is reloaded on
|
5
|
+
# every request. This slows down response time but is perfect for development
|
6
|
+
# since you don't have to restart the webserver when you make code changes.
|
7
|
+
config.cache_classes = false
|
8
|
+
|
9
|
+
# Log error messages when you accidentally call methods on nil.
|
10
|
+
# config.whiny_nils = true
|
11
|
+
|
12
|
+
# Show full error reports and disable caching
|
13
|
+
config.consider_all_requests_local = true
|
14
|
+
config.action_view.debug_rjs = true
|
15
|
+
config.action_controller.perform_caching = false
|
16
|
+
|
17
|
+
# Don't care if the mailer can't send
|
18
|
+
config.action_mailer.raise_delivery_errors = false
|
19
|
+
|
20
|
+
config.eager_load = false
|
21
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
RailsApp::Application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/environment.rb
|
3
|
+
|
4
|
+
# The production environment is meant for finished, "live" apps.
|
5
|
+
# Code is not reloaded between requests
|
6
|
+
config.cache_classes = true
|
7
|
+
|
8
|
+
# Full error reports are disabled and caching is turned on
|
9
|
+
config.consider_all_requests_local = false
|
10
|
+
config.action_controller.perform_caching = true
|
11
|
+
|
12
|
+
# See everything in the log (default is :info)
|
13
|
+
# config.log_level = :debug
|
14
|
+
|
15
|
+
# Use a different logger for distributed setups
|
16
|
+
# config.logger = SyslogLogger.new
|
17
|
+
|
18
|
+
# Use a different cache store in production
|
19
|
+
# config.cache_store = :mem_cache_store
|
20
|
+
|
21
|
+
# Disable Rails's static asset server
|
22
|
+
# In production, Apache or nginx will already do this
|
23
|
+
config.serve_static_assets = false
|
24
|
+
|
25
|
+
# Enable serving of images, stylesheets, and javascripts from an asset server
|
26
|
+
# config.action_controller.asset_host = "http://assets.example.com"
|
27
|
+
|
28
|
+
# Disable delivery errors, bad email addresses will be ignored
|
29
|
+
# config.action_mailer.raise_delivery_errors = false
|
30
|
+
|
31
|
+
# Enable threaded mode
|
32
|
+
# config.threadsafe!
|
33
|
+
|
34
|
+
config.eager_load = true
|
35
|
+
end
|
@@ -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,21 @@
|
|
1
|
+
ENV['RAILS_ENV'] = 'test'
|
2
|
+
|
3
|
+
if Bundler.definition.dependencies.map(&:name).include?('protected_attributes')
|
4
|
+
require 'protected_attributes'
|
5
|
+
end
|
6
|
+
require 'rails_app/config/environment'
|
7
|
+
require 'rspec/rails'
|
8
|
+
require 'audited'
|
9
|
+
require 'audited_spec_helpers'
|
10
|
+
require 'support/active_record/models'
|
11
|
+
load "audited/sweeper.rb" # force to reload sweeper
|
12
|
+
|
13
|
+
SPEC_ROOT = Pathname.new(File.expand_path('../', __FILE__))
|
14
|
+
|
15
|
+
Dir[SPEC_ROOT.join('support/*.rb')].each{|f| require f }
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
config.include AuditedSpecHelpers
|
19
|
+
config.use_transactional_fixtures = false if Rails.version.start_with?('4.')
|
20
|
+
config.use_transactional_tests = false if config.respond_to?(:use_transactional_tests=)
|
21
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require File.expand_path('../schema', __FILE__)
|
3
|
+
|
4
|
+
module Models
|
5
|
+
module ActiveRecord
|
6
|
+
class User < ::ActiveRecord::Base
|
7
|
+
audited allow_mass_assignment: true, except: :password
|
8
|
+
|
9
|
+
attr_protected :logins if respond_to?(:attr_protected)
|
10
|
+
|
11
|
+
def name=(val)
|
12
|
+
write_attribute(:name, CGI.escapeHTML(val))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class UserOnlyPassword < ::ActiveRecord::Base
|
17
|
+
self.table_name = :users
|
18
|
+
audited allow_mass_assignment: true, only: :password
|
19
|
+
end
|
20
|
+
|
21
|
+
class CommentRequiredUser < ::ActiveRecord::Base
|
22
|
+
self.table_name = :users
|
23
|
+
audited comment_required: true
|
24
|
+
end
|
25
|
+
|
26
|
+
class AccessibleAfterDeclarationUser < ::ActiveRecord::Base
|
27
|
+
self.table_name = :users
|
28
|
+
audited
|
29
|
+
attr_accessible :name, :username, :password if respond_to?(:attr_accessible)
|
30
|
+
end
|
31
|
+
|
32
|
+
class AccessibleBeforeDeclarationUser < ::ActiveRecord::Base
|
33
|
+
self.table_name = :users
|
34
|
+
attr_accessible :name, :username, :password if respond_to?(:attr_accessible) # declare attr_accessible before calling aaa
|
35
|
+
audited
|
36
|
+
end
|
37
|
+
|
38
|
+
class NoAttributeProtectionUser < ::ActiveRecord::Base
|
39
|
+
self.table_name = :users
|
40
|
+
audited allow_mass_assignment: true
|
41
|
+
end
|
42
|
+
|
43
|
+
class UserWithAfterAudit < ::ActiveRecord::Base
|
44
|
+
self.table_name = :users
|
45
|
+
audited
|
46
|
+
attr_accessor :bogus_attr, :around_attr
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def after_audit
|
51
|
+
self.bogus_attr = "do something"
|
52
|
+
end
|
53
|
+
|
54
|
+
def around_audit
|
55
|
+
self.around_attr = yield
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Company < ::ActiveRecord::Base
|
60
|
+
audited
|
61
|
+
end
|
62
|
+
|
63
|
+
class Company::STICompany < Company
|
64
|
+
end
|
65
|
+
|
66
|
+
class Owner < ::ActiveRecord::Base
|
67
|
+
self.table_name = 'users'
|
68
|
+
has_associated_audits
|
69
|
+
has_many :companies, class_name: "OwnedCompany", dependent: :destroy
|
70
|
+
end
|
71
|
+
|
72
|
+
class OwnedCompany < ::ActiveRecord::Base
|
73
|
+
self.table_name = 'companies'
|
74
|
+
belongs_to :owner, class_name: "Owner"
|
75
|
+
attr_accessible :name, :owner if respond_to?(:attr_accessible) # declare attr_accessible before calling aaa
|
76
|
+
audited associated_with: :owner
|
77
|
+
end
|
78
|
+
|
79
|
+
class OnUpdateDestroy < ::ActiveRecord::Base
|
80
|
+
self.table_name = 'companies'
|
81
|
+
audited on: [:update, :destroy]
|
82
|
+
end
|
83
|
+
|
84
|
+
class OnCreateDestroy < ::ActiveRecord::Base
|
85
|
+
self.table_name = 'companies'
|
86
|
+
audited on: [:create, :destroy]
|
87
|
+
end
|
88
|
+
|
89
|
+
class OnCreateDestroyExceptName < ::ActiveRecord::Base
|
90
|
+
self.table_name = 'companies'
|
91
|
+
audited except: :name, on: [:create, :destroy]
|
92
|
+
end
|
93
|
+
|
94
|
+
class OnCreateUpdate < ::ActiveRecord::Base
|
95
|
+
self.table_name = 'companies'
|
96
|
+
audited on: [:create, :update]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
begin
|
5
|
+
db_config = ActiveRecord::Base.configurations[Rails.env].clone
|
6
|
+
db_type = db_config['adapter']
|
7
|
+
db_name = db_config.delete('database')
|
8
|
+
raise Exception.new('No database name specified.') if db_name.blank?
|
9
|
+
if db_type == 'sqlite3'
|
10
|
+
db_file = Pathname.new(__FILE__).dirname.join(db_name)
|
11
|
+
db_file.unlink if db_file.file?
|
12
|
+
else
|
13
|
+
if defined?(JRUBY_VERSION)
|
14
|
+
db_config.symbolize_keys!
|
15
|
+
db_config[:configure_connection] = false
|
16
|
+
end
|
17
|
+
adapter = ActiveRecord::Base.send("#{db_type}_connection", db_config)
|
18
|
+
adapter.recreate_database db_name
|
19
|
+
adapter.disconnect!
|
20
|
+
end
|
21
|
+
rescue Exception => e
|
22
|
+
Kernel.warn e
|
23
|
+
end
|
24
|
+
|
25
|
+
logfile = Pathname.new(__FILE__).dirname.join('debug.log')
|
26
|
+
logfile.unlink if logfile.file?
|
27
|
+
ActiveRecord::Base.logger = Logger.new(logfile)
|
28
|
+
|
29
|
+
ActiveRecord::Migration.verbose = false
|
30
|
+
ActiveRecord::Base.establish_connection
|
31
|
+
|
32
|
+
ActiveRecord::Schema.define do
|
33
|
+
create_table :users do |t|
|
34
|
+
t.column :name, :string
|
35
|
+
t.column :username, :string
|
36
|
+
t.column :password, :string
|
37
|
+
t.column :activated, :boolean
|
38
|
+
t.column :suspended_at, :datetime
|
39
|
+
t.column :logins, :integer, default: 0
|
40
|
+
t.column :created_at, :datetime
|
41
|
+
t.column :updated_at, :datetime
|
42
|
+
end
|
43
|
+
|
44
|
+
create_table :companies do |t|
|
45
|
+
t.column :name, :string
|
46
|
+
t.column :owner_id, :integer
|
47
|
+
t.column :type, :string
|
48
|
+
end
|
49
|
+
|
50
|
+
create_table :authors do |t|
|
51
|
+
t.column :name, :string
|
52
|
+
end
|
53
|
+
|
54
|
+
create_table :books do |t|
|
55
|
+
t.column :authord_id, :integer
|
56
|
+
t.column :title, :string
|
57
|
+
end
|
58
|
+
|
59
|
+
create_table :audits do |t|
|
60
|
+
t.column :auditable_id, :integer
|
61
|
+
t.column :auditable_type, :string
|
62
|
+
t.column :associated_id, :integer
|
63
|
+
t.column :associated_type, :string
|
64
|
+
t.column :user_id, :integer
|
65
|
+
t.column :user_type, :string
|
66
|
+
t.column :username, :string
|
67
|
+
t.column :action, :string
|
68
|
+
t.column :audited_changes, :text
|
69
|
+
t.column :version, :integer, default: 0
|
70
|
+
t.column :comment, :string
|
71
|
+
t.column :remote_address, :string
|
72
|
+
t.column :request_uuid, :string
|
73
|
+
t.column :created_at, :datetime
|
74
|
+
end
|
75
|
+
|
76
|
+
add_index :audits, [:auditable_id, :auditable_type], name: 'auditable_index'
|
77
|
+
add_index :audits, [:associated_id, :associated_type], name: 'associated_index'
|
78
|
+
add_index :audits, [:user_id, :user_type], name: 'user_index'
|
79
|
+
add_index :audits, :request_uuid
|
80
|
+
add_index :audits, :created_at
|
81
|
+
end
|