rails_validation_api 0.1.0
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 +7 -0
- data/exe/rails_validation_api +131 -0
- data/lib/auto_load_rails_validation_api.rb +72 -0
- data/lib/error/custom_error.rb +11 -0
- data/lib/rails_validation_api/dsl.rb +28 -0
- data/lib/rails_validation_api/validator.rb +89 -0
- data/lib/rails_validation_api/version.rb +3 -0
- data/lib/rails_validation_api.rb +34 -0
- metadata +107 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 00afcf5c271e4cb83d53f8f5cb0b7a92c1564222d3b505862e74eecfde47d0e9
|
4
|
+
data.tar.gz: 8d964b0829f1e0402f561e6d4e20bb0382ce2d573ae10d8857567ab636700c2e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cf86fa4a1ee9a5931346d3d7effda41c07a69ed9886107e9d4d9316d4dbb8fa7bf20fc16cd5639d204858b637bb86d49f3a21f039214204c733359b3f689cee6
|
7
|
+
data.tar.gz: 2a5f164d626457756e0f927f663d7a52ca1b771b4b69ada411bbc9bee402f95d0832f92b6a34e74c4c9aace7d843d346dad86f0911f358ce1b14884abbb03494
|
@@ -0,0 +1,131 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "active_support/core_ext/string/inflections"
|
4
|
+
require "fileutils"
|
5
|
+
require "debug"
|
6
|
+
|
7
|
+
COMMAND = ARGV.shift
|
8
|
+
NAME = ARGV.shift&.downcase
|
9
|
+
|
10
|
+
def usage
|
11
|
+
puts <<~TEXT
|
12
|
+
Usage:
|
13
|
+
rails_validation_api install
|
14
|
+
rails_validation_api generate [validator_name]
|
15
|
+
rails_validation_api destroy [validator_name]
|
16
|
+
Example:
|
17
|
+
rails_validation_api generate purchaseorder
|
18
|
+
rails_validation_api destroy purchaseorder
|
19
|
+
TEXT
|
20
|
+
end
|
21
|
+
|
22
|
+
def check_inflection(name)
|
23
|
+
require_relative "../config/initializers/inflections"
|
24
|
+
if ActiveSupport::Inflector.inflections.acronyms.key?("api")
|
25
|
+
'API'
|
26
|
+
else
|
27
|
+
'Api'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def generate_parameter_validator(name)
|
32
|
+
api = check_inflection(name)
|
33
|
+
class_name = "#{name.camelize}Validator"
|
34
|
+
path = "app/validators/api/validate_parameters/#{name}_validator.rb"
|
35
|
+
|
36
|
+
FileUtils.mkdir_p(File.dirname(path))
|
37
|
+
|
38
|
+
if File.exist?(path)
|
39
|
+
puts "⚠️ Validator already exists at #{path}"
|
40
|
+
else
|
41
|
+
File.write(path, <<~RUBY)
|
42
|
+
# frozen_string_literal: true
|
43
|
+
|
44
|
+
class #{api}::ValidateParameters::#{class_name}
|
45
|
+
FIELDS_VALIDATES = {
|
46
|
+
# account_id_validate:
|
47
|
+
# {
|
48
|
+
# field: :account_id, type: Integer, opts: [
|
49
|
+
# { required: true, message: "Account id is required" }
|
50
|
+
# ]
|
51
|
+
# }
|
52
|
+
}.freeze
|
53
|
+
|
54
|
+
def index
|
55
|
+
[
|
56
|
+
# FIELDS_VALIDATES[:account_id_validate]
|
57
|
+
]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
RUBY
|
61
|
+
|
62
|
+
puts "✅ Created #{path}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def destroy_validator(name)
|
67
|
+
params_path = "app/validators/api/validate_parameters/#{name}_validator.rb"
|
68
|
+
path = "app/validators/api/#{name}_validator.rb"
|
69
|
+
|
70
|
+
if File.exist?(path)
|
71
|
+
File.delete(path)
|
72
|
+
puts "🗑️ Deleted #{path}"
|
73
|
+
else
|
74
|
+
puts "⚠️ File not found: #{path}"
|
75
|
+
end
|
76
|
+
if File.exist?(params_path)
|
77
|
+
File.delete(params_path)
|
78
|
+
puts "🗑️ Deleted #{params_path}"
|
79
|
+
else
|
80
|
+
puts "⚠️ File not found: #{params_path}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def generate_validator(name)
|
85
|
+
api = check_inflection(name)
|
86
|
+
class_name = "#{name.camelize}Validator"
|
87
|
+
path = "app/validators/api/#{name}_validator.rb"
|
88
|
+
|
89
|
+
FileUtils.mkdir_p(File.dirname(path))
|
90
|
+
|
91
|
+
if File.exist?(path)
|
92
|
+
puts "⚠️ Validator already exists at #{path}"
|
93
|
+
else
|
94
|
+
File.write(path, <<~RUBY)
|
95
|
+
# frozen_string_literal: true
|
96
|
+
|
97
|
+
class #{api}::#{class_name}
|
98
|
+
def initialize(model_name, account)
|
99
|
+
@model_name = model_name
|
100
|
+
@account = account
|
101
|
+
end
|
102
|
+
|
103
|
+
def index(opts)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
RUBY
|
107
|
+
|
108
|
+
puts "✅ Created #{path}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
case COMMAND
|
113
|
+
when "install"
|
114
|
+
puts "🚀 Installing rails_validation_api..."
|
115
|
+
generate_validator("application")
|
116
|
+
when "generate"
|
117
|
+
if NAME.nil?
|
118
|
+
puts "❌ Please provide a name. Example: rails_validation_api generate purchaseorder"
|
119
|
+
else
|
120
|
+
generate_parameter_validator(NAME)
|
121
|
+
generate_validator(NAME)
|
122
|
+
end
|
123
|
+
when "destroy"
|
124
|
+
if NAME.nil?
|
125
|
+
puts "❌ Please provide a name. Example: rails_validation_api generate purchaseorder"
|
126
|
+
else
|
127
|
+
destroy_validator(NAME)
|
128
|
+
end
|
129
|
+
else
|
130
|
+
usage
|
131
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module AutoLoadRailsValidationApi
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
before_action :set_validation_context
|
7
|
+
before_action :auto_load_method
|
8
|
+
end
|
9
|
+
|
10
|
+
def auto_load_method
|
11
|
+
call_validator
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def set_validation_context
|
17
|
+
@params = params
|
18
|
+
@controller = controller_name
|
19
|
+
@action = action_name
|
20
|
+
@model_name = controller_name.classify
|
21
|
+
@account = Current.account rescue nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_validator
|
25
|
+
klass = Module.const_get(validator_name) rescue nil
|
26
|
+
param_klass = Module.const_get(param_object_validator_name) rescue nil
|
27
|
+
|
28
|
+
@validator = klass.new(@model_name, @account) if klass.present?
|
29
|
+
@param_validator = param_klass.new if param_klass.present?
|
30
|
+
end
|
31
|
+
|
32
|
+
def validator_name
|
33
|
+
"API::#{@model_name}Validator"
|
34
|
+
end
|
35
|
+
|
36
|
+
def param_object_validator_name
|
37
|
+
"API::ValidateParameters::#{@model_name}Validator"
|
38
|
+
end
|
39
|
+
|
40
|
+
def call_validator(action: nil, opts: {})
|
41
|
+
set_validator
|
42
|
+
action = (action || action_name).to_sym
|
43
|
+
opts = opts.blank? ? params : opts
|
44
|
+
rules = @param_validator.send(action) rescue nil
|
45
|
+
if rules.present?
|
46
|
+
validator = RailsValidationApi::Validator.new(params, rules)
|
47
|
+
validator.validate
|
48
|
+
end
|
49
|
+
get_params = @validator.method(action).arity rescue nil
|
50
|
+
|
51
|
+
return get_params if get_params.nil?
|
52
|
+
|
53
|
+
if get_params == 0
|
54
|
+
begin
|
55
|
+
@validator.send(action)
|
56
|
+
rescue NoMethodError => ex
|
57
|
+
nil
|
58
|
+
rescue Exception => ex
|
59
|
+
raise RailsValidationApi::Error.new(ex.status, ex.message)
|
60
|
+
end
|
61
|
+
else
|
62
|
+
begin
|
63
|
+
@validator.send(action, opts)
|
64
|
+
rescue NoMethodError => ex
|
65
|
+
nil
|
66
|
+
rescue => ex
|
67
|
+
status_code = ex.is_a?(ActiveRecord::RecordNotFound) ? :not_found : ex.status
|
68
|
+
raise RailsValidationApi::Error.new(status_code, ex.message)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsValidationApi
|
4
|
+
class DSL
|
5
|
+
attr_reader :rules
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@rules = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def param!(name, type, **opts, &block)
|
12
|
+
key = :"#{name}_validate"
|
13
|
+
rule = { field: name, type: type, opts: [opts].compact }
|
14
|
+
|
15
|
+
if block_given?
|
16
|
+
nested = DSL.new
|
17
|
+
nested.instance_eval(&block)
|
18
|
+
rule[:items] = nested.rules.values
|
19
|
+
end
|
20
|
+
|
21
|
+
@rules[key] = rule
|
22
|
+
end
|
23
|
+
|
24
|
+
# def rules
|
25
|
+
# @rules
|
26
|
+
# end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require "date"
|
2
|
+
require "time"
|
3
|
+
require "bigdecimal"
|
4
|
+
require "active_support/all"
|
5
|
+
|
6
|
+
module RailsValidationApi
|
7
|
+
class Validator
|
8
|
+
include RailsParam
|
9
|
+
|
10
|
+
attr_accessor :params
|
11
|
+
attr_reader :errors
|
12
|
+
|
13
|
+
def initialize(params, rules)
|
14
|
+
self.params = params.is_a?(ActionController::Parameters) ? params.to_unsafe_h : params
|
15
|
+
@rules = rules
|
16
|
+
@errors = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def validate
|
20
|
+
return false if @rules.nil? || @rules.empty?
|
21
|
+
|
22
|
+
@rules.each do |rule_name, rule|
|
23
|
+
validate_field(rule_name)
|
24
|
+
end
|
25
|
+
if @errors.any?
|
26
|
+
@errors.each do |error|
|
27
|
+
raise RailsValidationApi::Error.new(error[:field], :unprocessable_entity, error[:message])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def validate_field(rule)
|
35
|
+
return unless rule.is_a?(Hash)
|
36
|
+
|
37
|
+
field = rule[:field]
|
38
|
+
type = rule[:type]
|
39
|
+
opts = rule[:opts] || []
|
40
|
+
items = rule[:items]
|
41
|
+
|
42
|
+
return unless field && type
|
43
|
+
|
44
|
+
# Validate the main field
|
45
|
+
opts.each do |opt|
|
46
|
+
next unless opt.is_a?(Hash)
|
47
|
+
|
48
|
+
begin
|
49
|
+
param! field, type, **opt
|
50
|
+
rescue RailsParam::Param::InvalidParameterError => e
|
51
|
+
message = (e.message).include?(type.to_s) ? e.message : opt[:message]
|
52
|
+
@errors << { field: field, message: message }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Validate nested items if present (for Hash/Array fields)
|
57
|
+
if items && params[field].is_a?(Hash)
|
58
|
+
validate_nested_items(field, items, params[field])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def validate_nested_items(parent_field, items, nested_params)
|
63
|
+
return unless items.is_a?(Array)
|
64
|
+
|
65
|
+
items.each do |item_rule|
|
66
|
+
next unless item_rule.is_a?(Hash)
|
67
|
+
|
68
|
+
item_field = item_rule[:field]
|
69
|
+
item_type = item_rule[:type]
|
70
|
+
item_opts = item_rule[:opts] || []
|
71
|
+
|
72
|
+
next unless item_field && item_type
|
73
|
+
|
74
|
+
# Create a temporary validator for nested validation
|
75
|
+
temp_validator = self.class.new(nested_params, {})
|
76
|
+
item_opts.each do |opt|
|
77
|
+
next unless opt.is_a?(Hash)
|
78
|
+
|
79
|
+
begin
|
80
|
+
temp_validator.param! item_field, item_type, **opt
|
81
|
+
rescue RailsParam::Param::InvalidParameterError => e
|
82
|
+
message = (e.message).include?(item_type.to_s) ? e.message : opt[:message]
|
83
|
+
@errors << { field: "#{parent_field}.#{item_field}", message: message }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
require "active_model"
|
5
|
+
require "active_support"
|
6
|
+
require "rails_param"
|
7
|
+
require "active_support/core_ext/hash"
|
8
|
+
require_relative "rails_validation_api/dsl"
|
9
|
+
require_relative "rails_validation_api/validator"
|
10
|
+
require "active_support/concern"
|
11
|
+
require "active_support/core_ext/string/inflections"
|
12
|
+
require "rails_param"
|
13
|
+
require "date"
|
14
|
+
require "time"
|
15
|
+
require "bigdecimal"
|
16
|
+
require "active_support/all"
|
17
|
+
|
18
|
+
module RailsValidationApi
|
19
|
+
class Error < StandardError
|
20
|
+
attr_reader :field, :status, :additional_info
|
21
|
+
def initialize(field = :base, status = :unprocessable_entity, message = nil, additional_info: nil)
|
22
|
+
@field = field
|
23
|
+
@status = status
|
24
|
+
@additional_info = additional_info
|
25
|
+
super(message || "Something went wrong")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.build(&block)
|
30
|
+
dsl = DSL.new
|
31
|
+
dsl.instance_eval(&block)
|
32
|
+
dsl.rules
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rails_validation_api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Linh Nguyen Quang
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-07-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rails_param
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
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: activemodel
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
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: debug
|
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
|
+
description: Provides a DSL to validate and permit params like Rails strong parameters
|
70
|
+
email:
|
71
|
+
- linhnq@gmail.com
|
72
|
+
executables:
|
73
|
+
- rails_validation_api
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- exe/rails_validation_api
|
78
|
+
- lib/auto_load_rails_validation_api.rb
|
79
|
+
- lib/error/custom_error.rb
|
80
|
+
- lib/rails_validation_api.rb
|
81
|
+
- lib/rails_validation_api/dsl.rb
|
82
|
+
- lib/rails_validation_api/validator.rb
|
83
|
+
- lib/rails_validation_api/version.rb
|
84
|
+
homepage: https://github.com/your_username/rails_validation_api
|
85
|
+
licenses:
|
86
|
+
- MIT
|
87
|
+
metadata: {}
|
88
|
+
post_install_message:
|
89
|
+
rdoc_options: []
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
requirements: []
|
103
|
+
rubygems_version: 3.4.6
|
104
|
+
signing_key:
|
105
|
+
specification_version: 4
|
106
|
+
summary: Strong parameter-style validation for Rails or plain Ruby apps
|
107
|
+
test_files: []
|