better_record 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/scaffold.css +80 -0
- data/app/controllers/better_record/application_controller.rb +1 -0
- data/app/controllers/better_record/table_sizes_controller.rb +28 -0
- data/app/helpers/better_record/table_sizes_helper.rb +4 -0
- data/app/models/better_record/base.rb +16 -8
- data/app/models/better_record/current.rb +5 -0
- data/app/models/better_record/{audit.rb → logged_action.rb} +2 -2
- data/app/models/better_record/table_size.rb +20 -17
- data/{lib/better_record → config/initializers/active_record}/associations.rb +5 -8
- data/config/initializers/active_record/reflection.rb +21 -0
- data/config/initializers/boolean.rb +11 -0
- data/config/initializers/content_security_policy.rb +25 -0
- data/config/initializers/filter_parameter_logging.rb +10 -0
- data/config/initializers/inflections.rb +21 -0
- data/config/initializers/integer.rb +5 -0
- data/config/initializers/jazz_fingers.rb +7 -0
- data/config/initializers/mime_types.rb +4 -0
- data/config/initializers/money_type.rb +32 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20180725160802_create_better_record_db_functions.rb +94 -0
- data/db/migrate/20180725201614_create_better_record_table_sizes.rb +24 -0
- data/db/postgres-audit-trigger.psql +347 -0
- data/lib/better_record.rb +14 -19
- data/lib/better_record/version.rb +1 -1
- data/lib/tasks/spec/attributes.rake +42 -0
- metadata +95 -9
- data/lib/generators/create_helper_functions/USAGE +0 -9
- data/lib/generators/create_helper_functions/create_helper_functions_generator.rb +0 -61
- data/lib/tasks/db/create_audits.rake +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 714bdfe5593dca0ec99aa991dc68e1c432f2ff730ad8c78bad43d6172714b10c
|
4
|
+
data.tar.gz: 05523c1546ac5d85673b2f8d9473dc2371f9d6bce315d4fb6aa77832b3cdedd9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b4fc40ce72b44600fe6a8167745f1a3147080ea38afecb84fe2bb35b599dc7b6ec22ba6f0b71963a020c08805fd5697437dadcfaaa592612f1032bf3195e88d
|
7
|
+
data.tar.gz: 1d40b47387cae6dbf65d539ae10aea6b29074b3837fc218604c407390f348df9b4cd7b8bf82981fa8a31a5f0f4603b7c685b3574547eb1058dd39f8bc8d7166a
|
@@ -0,0 +1,80 @@
|
|
1
|
+
body {
|
2
|
+
background-color: #fff;
|
3
|
+
color: #333;
|
4
|
+
margin: 33px;
|
5
|
+
}
|
6
|
+
|
7
|
+
body, p, ol, ul, td {
|
8
|
+
font-family: verdana, arial, helvetica, sans-serif;
|
9
|
+
font-size: 13px;
|
10
|
+
line-height: 18px;
|
11
|
+
}
|
12
|
+
|
13
|
+
pre {
|
14
|
+
background-color: #eee;
|
15
|
+
padding: 10px;
|
16
|
+
font-size: 11px;
|
17
|
+
}
|
18
|
+
|
19
|
+
a {
|
20
|
+
color: #000;
|
21
|
+
}
|
22
|
+
|
23
|
+
a:visited {
|
24
|
+
color: #666;
|
25
|
+
}
|
26
|
+
|
27
|
+
a:hover {
|
28
|
+
color: #fff;
|
29
|
+
background-color: #000;
|
30
|
+
}
|
31
|
+
|
32
|
+
th {
|
33
|
+
padding-bottom: 5px;
|
34
|
+
}
|
35
|
+
|
36
|
+
td {
|
37
|
+
padding: 0 5px 7px;
|
38
|
+
}
|
39
|
+
|
40
|
+
div.field,
|
41
|
+
div.actions {
|
42
|
+
margin-bottom: 10px;
|
43
|
+
}
|
44
|
+
|
45
|
+
#notice {
|
46
|
+
color: green;
|
47
|
+
}
|
48
|
+
|
49
|
+
.field_with_errors {
|
50
|
+
padding: 2px;
|
51
|
+
background-color: red;
|
52
|
+
display: table;
|
53
|
+
}
|
54
|
+
|
55
|
+
#error_explanation {
|
56
|
+
width: 450px;
|
57
|
+
border: 2px solid red;
|
58
|
+
padding: 7px 7px 0;
|
59
|
+
margin-bottom: 20px;
|
60
|
+
background-color: #f0f0f0;
|
61
|
+
}
|
62
|
+
|
63
|
+
#error_explanation h2 {
|
64
|
+
text-align: left;
|
65
|
+
font-weight: bold;
|
66
|
+
padding: 5px 5px 5px 15px;
|
67
|
+
font-size: 12px;
|
68
|
+
margin: -7px -7px 0;
|
69
|
+
background-color: #c00;
|
70
|
+
color: #fff;
|
71
|
+
}
|
72
|
+
|
73
|
+
#error_explanation ul li {
|
74
|
+
font-size: 12px;
|
75
|
+
list-style: square;
|
76
|
+
}
|
77
|
+
|
78
|
+
label {
|
79
|
+
display: block;
|
80
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_dependency "better_record/application_controller"
|
2
|
+
|
3
|
+
module BetterRecord
|
4
|
+
class TableSizesController < ApplicationController
|
5
|
+
before_action :set_table_size, only: [:show]
|
6
|
+
|
7
|
+
# GET /table_sizes
|
8
|
+
def index
|
9
|
+
TableSize.reload_data if Boolean.parse(params[:reload])
|
10
|
+
@table_sizes = TableSize.all
|
11
|
+
end
|
12
|
+
|
13
|
+
# GET /table_sizes/1
|
14
|
+
def show
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
# Use callbacks to share common setup or constraints between actions.
|
19
|
+
def set_table_size
|
20
|
+
@table_size = TableSize.find_by(oid: params[:id])
|
21
|
+
end
|
22
|
+
|
23
|
+
# Only allow a trusted parameter "white list" through.
|
24
|
+
def table_size_params
|
25
|
+
params.fetch(:table_size, {})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -9,14 +9,6 @@ module BetterRecord
|
|
9
9
|
# == Extensions ===========================================================
|
10
10
|
|
11
11
|
# == Relationships ========================================================
|
12
|
-
if (ha = BetterRecord.has_audits_by_default)
|
13
|
-
has_many :audits,
|
14
|
-
class_name: 'BetterRecord::Audit',
|
15
|
-
primary_type: :table_name,
|
16
|
-
foreign_key: :row_id,
|
17
|
-
foreign_type: :table_name,
|
18
|
-
as: :audits
|
19
|
-
end
|
20
12
|
|
21
13
|
# == Validations ==========================================================
|
22
14
|
before_validation :set_booleans
|
@@ -26,6 +18,10 @@ module BetterRecord
|
|
26
18
|
# == Callbacks ============================================================
|
27
19
|
|
28
20
|
# == Class Methods ========================================================
|
21
|
+
def self.audit_relation_name
|
22
|
+
@@audit_relation_name ||= (BetterRecord.audit_relation_name.presence || :audits).to_sym
|
23
|
+
end
|
24
|
+
|
29
25
|
def self.boolean_columns
|
30
26
|
[]
|
31
27
|
end
|
@@ -133,6 +129,10 @@ module BetterRecord
|
|
133
129
|
self.class.boolean_columns
|
134
130
|
end
|
135
131
|
|
132
|
+
def default_print
|
133
|
+
self.class.default_print
|
134
|
+
end
|
135
|
+
|
136
136
|
private
|
137
137
|
# def table_name_has_schema?
|
138
138
|
# self.class.table_name_has_schema?
|
@@ -153,5 +153,13 @@ module BetterRecord
|
|
153
153
|
true
|
154
154
|
end
|
155
155
|
|
156
|
+
if (ha = BetterRecord.has_audits_by_default)
|
157
|
+
has_many self.audit_relation_name,
|
158
|
+
class_name: 'BetterRecord::LoggedAction',
|
159
|
+
primary_type: :table_name,
|
160
|
+
foreign_key: :row_id,
|
161
|
+
foreign_type: :table_name,
|
162
|
+
as: self.audit_relation_name
|
163
|
+
end
|
156
164
|
end
|
157
165
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module BetterRecord
|
2
|
-
class
|
2
|
+
class LoggedAction < Base
|
3
3
|
# == Constants ============================================================
|
4
4
|
ACTIONS = {
|
5
5
|
D: 'DELETE',
|
@@ -9,7 +9,7 @@ module BetterRecord
|
|
9
9
|
}.with_indifferent_access
|
10
10
|
|
11
11
|
# == Attributes ===========================================================
|
12
|
-
self.table_name =
|
12
|
+
self.table_name = "#{BetterRecord.db_audit_schema}.logged_actions"
|
13
13
|
|
14
14
|
# == Extensions ===========================================================
|
15
15
|
|
@@ -1,9 +1,12 @@
|
|
1
1
|
module BetterRecord
|
2
2
|
class TableSize < Base
|
3
3
|
# == Constants ============================================================
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
LOAD_TABLE_DATA_SQL = <<-SQL
|
5
|
+
BEGIN WORK;
|
6
|
+
LOCK #{BetterRecord.db_audit_schema}.table_sizes;
|
7
|
+
TRUNCATE #{BetterRecord.db_audit_schema}.table_sizes;
|
8
|
+
INSERT INTO #{BetterRecord.db_audit_schema}.table_sizes
|
9
|
+
(
|
7
10
|
SELECT
|
8
11
|
*,
|
9
12
|
pg_size_pretty(total_bytes) AS total,
|
@@ -16,21 +19,22 @@ module BetterRecord
|
|
16
19
|
total_bytes - idx_bytes - COALESCE(toast_bytes,0) AS tbl_bytes
|
17
20
|
FROM (
|
18
21
|
SELECT c.oid,nspname AS schema, relname AS name
|
19
|
-
, c.reltuples AS
|
22
|
+
, c.reltuples AS apx_row_count
|
20
23
|
, pg_total_relation_size(c.oid) AS total_bytes
|
21
24
|
, pg_indexes_size(c.oid) AS idx_bytes
|
22
25
|
, pg_total_relation_size(reltoastrelid) AS toast_bytes
|
23
26
|
FROM pg_class c
|
24
27
|
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
25
28
|
WHERE relkind = 'r'
|
26
|
-
)
|
27
|
-
)
|
28
|
-
)
|
29
|
+
) tmp_table_sizes
|
30
|
+
) tmp_table_sizes
|
31
|
+
);
|
32
|
+
COMMIT WORK;
|
29
33
|
SQL
|
30
34
|
|
31
35
|
# == Attributes ===========================================================
|
32
36
|
self.primary_key = :oid
|
33
|
-
self.table_name =
|
37
|
+
self.table_name = "#{BetterRecord.db_audit_schema}.table_sizes"
|
34
38
|
|
35
39
|
# == Extensions ===========================================================
|
36
40
|
|
@@ -43,18 +47,17 @@ module BetterRecord
|
|
43
47
|
# == Callbacks ============================================================
|
44
48
|
|
45
49
|
# == Class Methods ========================================================
|
46
|
-
def self.
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
50
|
+
def self.find_by(*args)
|
51
|
+
reload_data
|
52
|
+
super *args
|
53
|
+
end
|
51
54
|
|
52
|
-
|
55
|
+
def self.reload_data
|
56
|
+
connection.execute LOAD_TABLE_DATA_SQL
|
53
57
|
end
|
54
58
|
|
55
|
-
def self.
|
56
|
-
|
57
|
-
super *args
|
59
|
+
def self.tmp_table_exists?
|
60
|
+
connection.query_values("SELECT temp_table_exists('tmp_table_sizes')").first
|
58
61
|
end
|
59
62
|
|
60
63
|
# def self.default_print
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module
|
1
|
+
module ActiveRecord
|
2
2
|
module Associations
|
3
3
|
class AssociationScope #:nodoc:
|
4
4
|
def self.get_bind_values(owner, chain)
|
@@ -7,12 +7,12 @@ module BetterRecord
|
|
7
7
|
|
8
8
|
binds << last_reflection.join_id_for(owner)
|
9
9
|
if last_reflection.type
|
10
|
-
binds << owner.class.__send__(last_reflection.options[:primary_type].presence ||
|
10
|
+
binds << owner.class.__send__(last_reflection.options[:primary_type].presence || :table_name)
|
11
11
|
end
|
12
12
|
|
13
13
|
chain.each_cons(2).each do |reflection, next_reflection|
|
14
14
|
if reflection.type
|
15
|
-
binds << next_reflection.klass.__send__(reflection.options[:primary_type].presence || next_reflection[:primary_type].presence ||
|
15
|
+
binds << next_reflection.klass.__send__(reflection.options[:primary_type].presence || next_reflection[:primary_type].presence || :table_name)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
binds
|
@@ -29,7 +29,7 @@ module BetterRecord
|
|
29
29
|
scope = apply_scope(scope, table, key, value)
|
30
30
|
|
31
31
|
if reflection.type
|
32
|
-
polymorphic_type = transform_value(owner.class.__send__(reflection.options[:primary_type].presence ||
|
32
|
+
polymorphic_type = transform_value(owner.class.__send__(reflection.options[:primary_type].presence || :table_name))
|
33
33
|
scope = apply_scope(scope, table, reflection.type, polymorphic_type)
|
34
34
|
end
|
35
35
|
|
@@ -46,7 +46,7 @@ module BetterRecord
|
|
46
46
|
constraint = table[key].eq(foreign_table[foreign_key])
|
47
47
|
|
48
48
|
if reflection.type
|
49
|
-
value = transform_value(next_reflection.klass.__send__(reflection.options[:primary_type].presence ||
|
49
|
+
value = transform_value(next_reflection.klass.__send__(reflection.options[:primary_type].presence || :table_name))
|
50
50
|
scope = apply_scope(scope, table, reflection.type, value)
|
51
51
|
end
|
52
52
|
|
@@ -62,9 +62,6 @@ module BetterRecord
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
class BelongsToAssociation
|
66
|
-
end
|
67
|
-
|
68
65
|
class BelongsToPolymorphicAssociation < BelongsToAssociation
|
69
66
|
def klass
|
70
67
|
type = owner[reflection.foreign_type]
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Reflection
|
3
|
+
class AbstractReflection
|
4
|
+
def join_scope(table, foreign_klass)
|
5
|
+
predicate_builder = predicate_builder(table)
|
6
|
+
scope_chain_items = join_scopes(table, predicate_builder)
|
7
|
+
klass_scope = klass_join_scope(table, predicate_builder)
|
8
|
+
|
9
|
+
if type
|
10
|
+
klass_scope.where!(type => foreign_klass.__send__(options[:primary_type] || :table_name))
|
11
|
+
end
|
12
|
+
|
13
|
+
scope_chain_items.inject(klass_scope, &:merge!)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class RuntimeReflection < AbstractReflection # :nodoc:
|
18
|
+
delegate :scope, :type, :constraints, :get_join_keys, :options, to: :@reflection
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# Define an application-wide content security policy
|
4
|
+
# For further information see the following documentation
|
5
|
+
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
|
6
|
+
|
7
|
+
# Rails.application.config.content_security_policy do |policy|
|
8
|
+
# policy.default_src :self, :https
|
9
|
+
# policy.font_src :self, :https, :data
|
10
|
+
# policy.img_src :self, :https, :data
|
11
|
+
# policy.object_src :none
|
12
|
+
# policy.script_src :self, :https
|
13
|
+
# policy.style_src :self, :https
|
14
|
+
|
15
|
+
# # Specify URI for violation reports
|
16
|
+
# # policy.report_uri "/csp-violation-report-endpoint"
|
17
|
+
# end
|
18
|
+
|
19
|
+
# If you are using UJS then enable automatic nonce generation
|
20
|
+
# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
|
21
|
+
|
22
|
+
# Report CSP violations to a specified URI
|
23
|
+
# For further information see the following documentation:
|
24
|
+
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
|
25
|
+
# Rails.application.config.content_security_policy_report_only = true
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# Configure sensitive parameters which will be filtered from the log file.
|
4
|
+
Rails.application.config.filter_parameters |= [
|
5
|
+
:password,
|
6
|
+
:password_confirmation,
|
7
|
+
:new_password,
|
8
|
+
:new_password_confirmation,
|
9
|
+
:register_secret
|
10
|
+
]
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# Add new inflection rules using the following format. Inflections
|
4
|
+
# are locale specific, and you may define rules for as many different
|
5
|
+
# locales as you wish. All of these examples are active by default:
|
6
|
+
# ActiveSupport::Inflector.inflections(:en) do |inflect|
|
7
|
+
# inflect.plural /^(ox)$/i, '\1en'
|
8
|
+
# inflect.singular /^(ox)en/i, '\1'
|
9
|
+
# inflect.irregular 'person', 'people'
|
10
|
+
# inflect.uncountable %w( fish sheep )
|
11
|
+
# end
|
12
|
+
|
13
|
+
# These inflection rules are supported but not enabled by default:
|
14
|
+
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
15
|
+
inflect.acronym 'API'
|
16
|
+
inflect.acronym 'APIs'
|
17
|
+
inflect.acronym 'DB'
|
18
|
+
inflect.acronym 'DBs'
|
19
|
+
inflect.acronym 'GNU'
|
20
|
+
inflect.acronym 'GNUs'
|
21
|
+
end
|