active_record_auto_validations 0.0.1 → 0.0.3
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/README.md +26 -0
- data/app/models/concerns/active_record_auto_validations/model_concern.rb +11 -0
- data/app/services/active_record_auto_validations/auto_unique_index.rb +41 -0
- data/app/services/active_record_auto_validations/auto_validate_model_class.rb +103 -0
- data/app/services/active_record_auto_validations/on_load.rb +9 -0
- data/config/routes.rb +1 -1
- data/lib/active_record_auto_validations/engine.rb +4 -4
- data/lib/active_record_auto_validations/version.rb +1 -1
- data/lib/active_record_auto_validations.rb +0 -1
- data/lib/tasks/{auto_validations_tasks.rake → active_record_auto_validations_tasks.rake} +0 -0
- metadata +106 -13
- data/app/assets/config/auto_validations_manifest.js +0 -1
- data/app/assets/stylesheets/auto_validations/application.css +0 -15
- data/app/controllers/auto_validations/application_controller.rb +0 -4
- data/app/helpers/auto_validations/application_helper.rb +0 -4
- data/app/jobs/auto_validations/application_job.rb +0 -4
- data/app/mailers/auto_validations/application_mailer.rb +0 -6
- data/app/models/auto_validations/application_record.rb +0 -5
- data/app/models/concerns/auto_validations/model_concern.rb +0 -7
- data/app/services/auto_validations/auto_validate_model_class.rb +0 -51
- data/app/views/layouts/auto_validations/application.html.erb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d82df8dff2fe3dd3b03523499df936304e262721ea812792749059393602b662
|
4
|
+
data.tar.gz: 2f34c86ef85893c79c215c8227458ab42e0503c46cca848527ddef8f71dc1642
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3cee5f5a370c5c800efc0976eea8a350bb08d75bb9eab11d6fab4446d7ca2eab18096777daeff71f790bf51dd228c2a6c12e1d961c4eeda03541f1055f2be11
|
7
|
+
data.tar.gz: f2eb99db19909b63de9de904a86f0dc9b119117c6391b27d5595e8b0ca0ad5c4013b3bfa164a2314dafe393e315ca148db60206f2a99fb79d593da69c382608f
|
data/README.md
CHANGED
@@ -21,6 +21,32 @@ Or install it yourself as:
|
|
21
21
|
$ gem install active_record_auto_validations
|
22
22
|
```
|
23
23
|
|
24
|
+
Add this initializer:
|
25
|
+
```ruby
|
26
|
+
Rails.autoloaders.main.on_load do |_klass_name, klass, _defined_by_file|
|
27
|
+
ActiveRecordAutoValidations::OnLoad.execute!(klass: klass)
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
To run auto-validations on all models you can add something like this to ApplicationRecord:
|
32
|
+
```ruby
|
33
|
+
class ApplicationRecord < ActiveRecord::Base
|
34
|
+
primary_abstract_class
|
35
|
+
|
36
|
+
def self.inherited(child)
|
37
|
+
super
|
38
|
+
child.include ActiveRecordAutoValidations::ModelConcern
|
39
|
+
end
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
To run auto-validations on a single model you can do this:
|
44
|
+
```ruby
|
45
|
+
class Project < ApplicationRecord
|
46
|
+
include ActiveRecordAutoValidations::ModelConcern
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
24
50
|
## Contributing
|
25
51
|
Contribution directions go here.
|
26
52
|
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module ActiveRecordAutoValidations::ModelConcern
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do |base|
|
5
|
+
# The actual loading needs to be done after the model has been fully loaded,
|
6
|
+
# so this is actually done through a "on_load"-callback in an initializer.
|
7
|
+
#
|
8
|
+
# Kind of a hack but haven't been able to find another way of doing this
|
9
|
+
base.instance_variable_set(:@active_record_auto_validations_marked, true)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class ActiveRecordAutoValidations::AutoUniqueIndex
|
2
|
+
def self.execute!(**args)
|
3
|
+
ActiveRecordAutoValidations::AutoUniqueIndex.new(**args).perform
|
4
|
+
end
|
5
|
+
|
6
|
+
attr_reader :columns, :index, :model_class
|
7
|
+
|
8
|
+
def initialize(columns:, index:, model_class:)
|
9
|
+
@columns = columns
|
10
|
+
@index = index
|
11
|
+
@model_class = model_class
|
12
|
+
end
|
13
|
+
|
14
|
+
def perform
|
15
|
+
model_class.validates last_column_name.to_sym, **validates_args
|
16
|
+
end
|
17
|
+
|
18
|
+
def index_columns
|
19
|
+
@index_columns ||= index.columns.map { |column_name| columns.find { |column| column.name == column_name } }
|
20
|
+
end
|
21
|
+
|
22
|
+
def last_column_name
|
23
|
+
@last_column_name ||= index.columns.last
|
24
|
+
end
|
25
|
+
|
26
|
+
def validates_args
|
27
|
+
rest_of_columns = index.columns.clone
|
28
|
+
rest_of_columns.pop
|
29
|
+
|
30
|
+
validates_args = {}
|
31
|
+
|
32
|
+
if rest_of_columns.length.positive?
|
33
|
+
validates_args[:uniqueness] ||= {}
|
34
|
+
validates_args[:uniqueness][:scope] = rest_of_columns
|
35
|
+
end
|
36
|
+
|
37
|
+
validates_args[:allow_blank] = true if index_columns.any?(&:null)
|
38
|
+
validates_args[:uniqueness] ||= true
|
39
|
+
validates_args
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
class ActiveRecordAutoValidations::AutoValidateModelClass
|
2
|
+
attr_reader :model_class
|
3
|
+
|
4
|
+
def self.execute!(model_class:)
|
5
|
+
ActiveRecordAutoValidations::AutoValidateModelClass.new(model_class: model_class).perform
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(model_class:)
|
9
|
+
@model_class = model_class
|
10
|
+
end
|
11
|
+
|
12
|
+
def perform
|
13
|
+
check_if_already_loaded_on_model_class!
|
14
|
+
register_loaded_on_model_class!
|
15
|
+
|
16
|
+
begin
|
17
|
+
columns
|
18
|
+
indexes
|
19
|
+
rescue ActiveRecord::StatementInvalid => e
|
20
|
+
# Database is probably not running - we need to ignore this to make stuff like db:migrate, db:schema:load work
|
21
|
+
Rails.logger.error { "AutoValidate: Ignoring error while loading columns, because database might not be initialized: #{e.message}" }
|
22
|
+
return
|
23
|
+
end
|
24
|
+
|
25
|
+
insert_active_record_auto_validations_from_columns!
|
26
|
+
insert_active_record_auto_validations_from_indexes!
|
27
|
+
end
|
28
|
+
|
29
|
+
def check_if_already_loaded_on_model_class!
|
30
|
+
auto_validations_loaded = model_class.instance_variable_get(:@_active_record_auto_validations_loaded)
|
31
|
+
|
32
|
+
raise "AutoValidations already loaded for #{model_class.name}" if auto_validations_loaded
|
33
|
+
end
|
34
|
+
|
35
|
+
def register_loaded_on_model_class!
|
36
|
+
model_class.instance_variable_set(:@_active_record_auto_validations_loaded, true)
|
37
|
+
end
|
38
|
+
|
39
|
+
def columns
|
40
|
+
@columns ||= model_class.columns
|
41
|
+
end
|
42
|
+
|
43
|
+
def indexes
|
44
|
+
@indexes ||= model_class.connection.indexes(model_class.table_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def insert_active_record_auto_validations_from_columns!
|
48
|
+
columns.each do |column|
|
49
|
+
next if column.name == "id" || column.name == "created_at" || column.name == "updated_at"
|
50
|
+
|
51
|
+
auto_validate_pesence_on_column!(column) if auto_validate_presence_on_column?(column)
|
52
|
+
auto_validate_max_length_on_column!(column) if auto_validate_max_length_on_column?(column)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def insert_active_record_auto_validations_from_indexes!
|
57
|
+
indexes.each do |index|
|
58
|
+
next unless index.unique
|
59
|
+
|
60
|
+
# Dont add uniqueness validation to ActsAsList position columns
|
61
|
+
if index.columns.include?("position") && model_class.respond_to?(:acts_as_list_top)
|
62
|
+
Rails.logger.info { "AutoValidate: Skipping unique validation on #{model_class.table_name}##{index.columns.join(",")} because it looks like ActsAsList" }
|
63
|
+
next
|
64
|
+
end
|
65
|
+
|
66
|
+
ActiveRecordAutoValidations::AutoUniqueIndex.execute!(columns: columns, model_class: model_class, index: index)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def presence_validation_exists_on_column?(column)
|
71
|
+
model_class.validators_on(column.name.to_sym).each do |validator|
|
72
|
+
return true if validator.kind == :presence
|
73
|
+
end
|
74
|
+
|
75
|
+
false
|
76
|
+
end
|
77
|
+
|
78
|
+
def auto_validate_presence_on_column?(column)
|
79
|
+
!column.null && !column.name.end_with?("_id") && column.default.nil? && !presence_validation_exists_on_column?(column)
|
80
|
+
end
|
81
|
+
|
82
|
+
def auto_validate_pesence_on_column!(column)
|
83
|
+
Rails.logger.info { "AutoValidate: Adding presence validation to #{model_class.table_name}##{column.name}" }
|
84
|
+
model_class.validates column.name.to_sym, presence: true
|
85
|
+
end
|
86
|
+
|
87
|
+
def auto_validate_max_length_on_column?(column)
|
88
|
+
column.type == :string && column.limit && !max_length_validation_exists_on_column?(column)
|
89
|
+
end
|
90
|
+
|
91
|
+
def auto_validate_max_length_on_column!(column)
|
92
|
+
Rails.logger.info { "AutoValidate: Adding maxlength of #{column.limit} validation to #{model_class.table_name}##{column.name}" }
|
93
|
+
model_class.validates column.name.to_sym, allow_blank: true, length: {maximum: column.limit}
|
94
|
+
end
|
95
|
+
|
96
|
+
def max_length_validation_exists_on_column?(column)
|
97
|
+
model_class.validators_on(column.name.to_sym).each do |validator|
|
98
|
+
return true if validator.kind == :length
|
99
|
+
end
|
100
|
+
|
101
|
+
false
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class ActiveRecordAutoValidations::OnLoad
|
2
|
+
def self.execute!(klass:)
|
3
|
+
# This callback is going to be called for all classes. We should only run auto-validations on the ones that have had the module included
|
4
|
+
# which is done through the marked-variable.
|
5
|
+
marked = klass.instance_variable_get(:@active_record_auto_validations_marked)
|
6
|
+
|
7
|
+
ActiveRecordAutoValidations::AutoValidateModelClass.execute!(model_class: klass) if marked
|
8
|
+
end
|
9
|
+
end
|
data/config/routes.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
ActiveRecordAutoValidations::Engine.routes.draw do
|
1
|
+
ActiveRecordAutoValidations::Engine.routes.draw do # rubocop:disable Lint/EmptyBlock
|
2
2
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
module ActiveRecordAutoValidations
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
module ActiveRecordAutoValidations; end
|
2
|
+
|
3
|
+
class ActiveRecordAutoValidations::Engine < ::Rails::Engine
|
4
|
+
isolate_namespace ActiveRecordAutoValidations
|
5
5
|
end
|
File without changes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_auto_validations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kaspernj
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -24,6 +24,104 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 7.0.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dotenv-rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: mysql2
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec-rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop-performance
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop-rails
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop-rspec
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
27
125
|
description: Scans ActiveRecord models and adds automatic validations based on null,
|
28
126
|
max length etc.
|
29
127
|
email:
|
@@ -35,21 +133,15 @@ files:
|
|
35
133
|
- MIT-LICENSE
|
36
134
|
- README.md
|
37
135
|
- Rakefile
|
38
|
-
- app/
|
39
|
-
- app/
|
40
|
-
- app/
|
41
|
-
- app/
|
42
|
-
- app/jobs/auto_validations/application_job.rb
|
43
|
-
- app/mailers/auto_validations/application_mailer.rb
|
44
|
-
- app/models/auto_validations/application_record.rb
|
45
|
-
- app/models/concerns/auto_validations/model_concern.rb
|
46
|
-
- app/services/auto_validations/auto_validate_model_class.rb
|
47
|
-
- app/views/layouts/auto_validations/application.html.erb
|
136
|
+
- app/models/concerns/active_record_auto_validations/model_concern.rb
|
137
|
+
- app/services/active_record_auto_validations/auto_unique_index.rb
|
138
|
+
- app/services/active_record_auto_validations/auto_validate_model_class.rb
|
139
|
+
- app/services/active_record_auto_validations/on_load.rb
|
48
140
|
- config/routes.rb
|
49
141
|
- lib/active_record_auto_validations.rb
|
50
142
|
- lib/active_record_auto_validations/engine.rb
|
51
143
|
- lib/active_record_auto_validations/version.rb
|
52
|
-
- lib/tasks/
|
144
|
+
- lib/tasks/active_record_auto_validations_tasks.rake
|
53
145
|
homepage: https://github.com/kaspernj/active_record_auto_validations
|
54
146
|
licenses:
|
55
147
|
- MIT
|
@@ -57,6 +149,7 @@ metadata:
|
|
57
149
|
homepage_uri: https://github.com/kaspernj/active_record_auto_validations
|
58
150
|
source_code_uri: https://github.com/kaspernj/active_record_auto_validations
|
59
151
|
changelog_uri: https://github.com/kaspernj/active_record_auto_validations
|
152
|
+
rubygems_mfa_required: 'true'
|
60
153
|
post_install_message:
|
61
154
|
rdoc_options: []
|
62
155
|
require_paths:
|
@@ -1 +0,0 @@
|
|
1
|
-
//= link_directory ../stylesheets/active_record_auto_validations .css
|
@@ -1,15 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
-
* listed below.
|
4
|
-
*
|
5
|
-
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
-
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
-
*
|
8
|
-
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
-
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
-
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
-
* It is generally better to create a new file per style scope.
|
12
|
-
*
|
13
|
-
*= require_tree .
|
14
|
-
*= require_self
|
15
|
-
*/
|
@@ -1,51 +0,0 @@
|
|
1
|
-
class ActiveRecordAutoValidations::AutoValidateModelClass < ApplicationService
|
2
|
-
attr_reader :model_class
|
3
|
-
|
4
|
-
def initialize(model_class:)
|
5
|
-
@model_class = model_class
|
6
|
-
end
|
7
|
-
|
8
|
-
def perform
|
9
|
-
begin
|
10
|
-
columns
|
11
|
-
rescue ActiveRecord::StatementInvalid => e
|
12
|
-
# Database is probably not running - we need to ignore this to make stuff like db:migrate, db:schema:load work
|
13
|
-
Rails.logger.error "AutoValidate: Ignoring error while loading columns, because database might not be initialized: #{e.message}"
|
14
|
-
return succeed!
|
15
|
-
end
|
16
|
-
|
17
|
-
insert_active_record_auto_validations!
|
18
|
-
succeed!
|
19
|
-
end
|
20
|
-
|
21
|
-
def columns
|
22
|
-
@columns ||= model_class.columns
|
23
|
-
end
|
24
|
-
|
25
|
-
def insert_active_record_auto_validations!
|
26
|
-
columns.each do |column|
|
27
|
-
next if column.name == "id" || column.name == "created_at" || column.name == "updated_at"
|
28
|
-
|
29
|
-
auto_validate_pesence_on_column!(column) if auto_validate_presence_on_column?(column)
|
30
|
-
auto_validate_max_length_on_column!(column) if auto_validate_max_length_on_column?(column)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def auto_validate_presence_on_column?(column)
|
35
|
-
!column.null && !column.name.end_with?("_id") && column.default.nil?
|
36
|
-
end
|
37
|
-
|
38
|
-
def auto_validate_pesence_on_column!(column)
|
39
|
-
Rails.logger.info "AutoValidate: Adding presence validation to #{model_class.table_name}##{column.name}"
|
40
|
-
model_class.validates column.name.to_sym, presence: true
|
41
|
-
end
|
42
|
-
|
43
|
-
def auto_validate_max_length_on_column?(column)
|
44
|
-
column.type == :string && column.limit
|
45
|
-
end
|
46
|
-
|
47
|
-
def auto_validate_max_length_on_column!(column)
|
48
|
-
Rails.logger.info "AutoValidate: Adding maxlength of #{column.limit} validation to #{model_class.table_name}##{column.name}"
|
49
|
-
model_class.validates column.name.to_sym, allow_blank: true, length: {maximum: column.limit}
|
50
|
-
end
|
51
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<title>Auto validations</title>
|
5
|
-
<%= csrf_meta_tags %>
|
6
|
-
<%= csp_meta_tag %>
|
7
|
-
|
8
|
-
<%= stylesheet_link_tag "active_record_auto_validations/application", media: "all" %>
|
9
|
-
</head>
|
10
|
-
<body>
|
11
|
-
|
12
|
-
<%= yield %>
|
13
|
-
|
14
|
-
</body>
|
15
|
-
</html>
|