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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/scaffold.css +80 -0
  3. data/app/controllers/better_record/application_controller.rb +1 -0
  4. data/app/controllers/better_record/table_sizes_controller.rb +28 -0
  5. data/app/helpers/better_record/table_sizes_helper.rb +4 -0
  6. data/app/models/better_record/base.rb +16 -8
  7. data/app/models/better_record/current.rb +5 -0
  8. data/app/models/better_record/{audit.rb → logged_action.rb} +2 -2
  9. data/app/models/better_record/table_size.rb +20 -17
  10. data/{lib/better_record → config/initializers/active_record}/associations.rb +5 -8
  11. data/config/initializers/active_record/reflection.rb +21 -0
  12. data/config/initializers/boolean.rb +11 -0
  13. data/config/initializers/content_security_policy.rb +25 -0
  14. data/config/initializers/filter_parameter_logging.rb +10 -0
  15. data/config/initializers/inflections.rb +21 -0
  16. data/config/initializers/integer.rb +5 -0
  17. data/config/initializers/jazz_fingers.rb +7 -0
  18. data/config/initializers/mime_types.rb +4 -0
  19. data/config/initializers/money_type.rb +32 -0
  20. data/config/routes.rb +2 -0
  21. data/db/migrate/20180725160802_create_better_record_db_functions.rb +94 -0
  22. data/db/migrate/20180725201614_create_better_record_table_sizes.rb +24 -0
  23. data/db/postgres-audit-trigger.psql +347 -0
  24. data/lib/better_record.rb +14 -19
  25. data/lib/better_record/version.rb +1 -1
  26. data/lib/tasks/spec/attributes.rake +42 -0
  27. metadata +95 -9
  28. data/lib/generators/create_helper_functions/USAGE +0 -9
  29. data/lib/generators/create_helper_functions/create_helper_functions_generator.rb +0 -61
  30. data/lib/tasks/db/create_audits.rake +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1f24408013032454f5f6384cfa1723d81fd5b741c544f35ce95352fe4c334a8
4
- data.tar.gz: 5476435865403fef0645f2502eaf10a412fe27d222b43568e5eb7f557f60f558
3
+ metadata.gz: 714bdfe5593dca0ec99aa991dc68e1c432f2ff730ad8c78bad43d6172714b10c
4
+ data.tar.gz: 05523c1546ac5d85673b2f8d9473dc2371f9d6bce315d4fb6aa77832b3cdedd9
5
5
  SHA512:
6
- metadata.gz: 307dc6781a0ae40f1d66ebb7f9e8ea7a4e4fec739554a314c0dceb4302b0f3bbaa928dfacf7b8649ec99b87bebd243ac107446d4ad4b61d5e91ef054d7156e6c
7
- data.tar.gz: 3fc5c79c31830dacda3dc341c18584ed0c30ede6aa915011c40bcad19acbb78a3c65c97b4ea3754324077c1edce7215bb6c3837a4e35f0382de9036e3d1199b6
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
+ }
@@ -1,5 +1,6 @@
1
1
  module BetterRecord
2
2
  class ApplicationController < ActionController::Base
3
3
  protect_from_forgery with: :exception
4
+ layout BetterRecord.layout_template.presence || 'better_record/application'
4
5
  end
5
6
  end
@@ -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
@@ -0,0 +1,4 @@
1
+ module BetterRecord
2
+ module TableSizesHelper
3
+ end
4
+ 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
@@ -0,0 +1,5 @@
1
+ module BetterRecord
2
+ class Current < ActiveSupport::CurrentAttributes
3
+ attribute :user, :ip_address
4
+ end
5
+ end
@@ -1,5 +1,5 @@
1
1
  module BetterRecord
2
- class Audit < Base
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 = 'audit.logged_actions'
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
- CREATE_TABLE_SQL = <<-SQL
5
- DROP TABLE IF EXISTS table_sizes;
6
- CREATE TEMPORARY TABLE table_sizes AS (
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 row_estimate
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
- ) table_sizes
27
- ) table_sizes
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 = 'table_sizes'
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.load_schema(reload = false)
47
- unless @loaded_schema && !reload
48
- connection.execute CREATE_TABLE_SQL
49
- @loaded_schema = true
50
- end
50
+ def self.find_by(*args)
51
+ reload_data
52
+ super *args
53
+ end
51
54
 
52
- super()
55
+ def self.reload_data
56
+ connection.execute LOAD_TABLE_DATA_SQL
53
57
  end
54
58
 
55
- def self.find_by(*args)
56
- load_schema(true)
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 BetterRecord
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 || BetterRecord.default_polymorphic_method.presence || :polymorphic_name)
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 || BetterRecord.default_polymorphic_method.presence || :polymorphic_name)
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 || BetterRecord.default_polymorphic_method.presence || :polymorphic_name))
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 || BetterRecord.default_polymorphic_method.presence || :polymorphic_name))
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,11 @@
1
+ class Boolean
2
+ def self.parse(value)
3
+ ActiveRecord::Type::Boolean.new.cast(value)
4
+ end
5
+ end
6
+
7
+ class Object
8
+ def yes_no_to_s
9
+ !!self == self ? (self ? 'yes' : 'no') : to_s
10
+ end
11
+ 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
@@ -0,0 +1,5 @@
1
+ class Integer
2
+ def cents
3
+ StoreAsInt.money(self)
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ if defined?(JazzFingers)
2
+ JazzFingers.configure do |config|
3
+ config.colored_prompt = true
4
+ config.awesome_print = true
5
+ config.coolline = false
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Add new mime types for use in respond_to blocks:
4
+ # Mime::Type.register "text/richtext", :rtf