better_record 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|