validate-params 0.7.0 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7626ebe2f24591c008739bce05f28938e39094dc057ce65b227e7f99130c21cc
4
- data.tar.gz: 10f86e031e06e0c8723792d399881d4cc9baa64d9841eca1a1123c13606519ea
3
+ metadata.gz: 5c5bfbff5338d3dc78e35032adb08de2f63d43e3205cc636e8657c9385ecdc11
4
+ data.tar.gz: 43d7c4db9adc552528f72de7a7d09ace99a12120860f9fc721ee8476bc201e7f
5
5
  SHA512:
6
- metadata.gz: b90773a69bdb7d7a8f65df932f78c3c0da3b4937540d4da8ca89695a0113548dffbe45760ff49ee0d6e89b718fb1d689c3f778a0887562290d2e5092956e13a7
7
- data.tar.gz: 18a1f5f2d8b0aec4210e8ad50f9d1a715e6f1aa01ab7cf74af77c4fffdbbe4b1f0c16a38b9b57a1df2a83cb3834bb7a9d908ff1b981a71206131e2c4ffaa7726
6
+ metadata.gz: 508ac950bf308b164b8724bf07687a3473a32b25d4eec3d2cec109bafe5b59eb23454838aa35e1e2a48da3cce011cd0def8168221316e51ec67b1aa595f2ad02
7
+ data.tar.gz: 36797b8c27c56aea0786cbc4fd9fee79933ff3b5762adc2de6c3a052ed48a380e20f6aa52e1afd9d7bb48988d151aee0af36c2a1ba00f5f04e5cec5121cdfe0f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.8.0] - 2023-05-30
4
+
5
+ - Added support for passing array of actions into validate_params_for to run on multiple actions
6
+ - Added support for Array type to use option reject_blank: true to remove blank values from array
7
+
3
8
  ## [0.7.0] - 2023-05-30
4
9
 
5
10
  - Added type support for casting params into types
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- validate-params (0.7.0)
4
+ validate-params (0.8.0)
5
5
  activesupport (>= 6.1.0)
6
6
  i18n (>= 1.6)
7
7
 
data/README.md CHANGED
@@ -27,7 +27,7 @@ class TestController < ActionController::Base
27
27
  p.param :occurred_on, Date, required: true, default: proc { Date.today }
28
28
  p.param :quantity, Integer, required: true, in: [1, 2, 3]
29
29
  p.param :user_ids, Array, of: Integer, default: [1, 2, 3]
30
- p.param :states, Array, of: String, default: ["active", "inactive"]
30
+ p.param :states, Array, of: String, default: ["active", "inactive"], reject_blank: true
31
31
  p.param :date_of_birth, Hash do |pp|
32
32
  pp.param :gt, Date
33
33
  pp.param :lt, Date
@@ -48,6 +48,18 @@ end
48
48
 
49
49
  If the parameters are valid, the controller action will be executed as normal. If the parameters are invalid, a **400 Bad Request** response will be returned with a JSON body containing the errors, or an empty HTML response.
50
50
 
51
+ ```json
52
+ {
53
+ "success": false,
54
+ "errors": [
55
+ {
56
+ "message": "hired_on must be a valid Date"
57
+ },
58
+
59
+ ]
60
+ }
61
+ ```
62
+
51
63
  ## Format
52
64
 
53
65
  By default responses are returned in JSON format. To return responses as an empty HTML response, change the :format options in the validate_params methods to :html.
@@ -3,17 +3,27 @@
3
3
  module ValidateParams
4
4
  module Validatable
5
5
  class ParamBuilder
6
- def initialize(parent_field = nil)
6
+ def initialize(parent_field: nil, validations:)
7
7
  @parent_field = parent_field
8
- @params_validations = []
8
+ @validations = validations
9
9
  end
10
10
 
11
- def param(field, type, options = {})
12
- return { field: field, type: type, options: options } if @parent_field.nil?
13
-
14
- @params_validations << { field: { @parent_field => field }, type: type, options: options }
15
- @params_validations
11
+ def param(field, type, options = {}, &block)
12
+ if block
13
+ yield(ParamBuilder.new(parent_field: field, validations: @validations))
14
+ else
15
+ @validations << build_config(field, type, options)
16
+ end
16
17
  end
18
+
19
+ private
20
+ def build_config(field, type, options)
21
+ if @parent_field.nil?
22
+ { field: field, type: type, options: options }
23
+ else
24
+ { field: { @parent_field => field }, type: type, options: options }
25
+ end
26
+ end
17
27
  end
18
28
  end
19
29
  end
@@ -61,7 +61,7 @@ module ValidateParams
61
61
  end
62
62
 
63
63
  def validate_inclusion
64
- return if @options[:in].include?(value)
64
+ return if @options[:in].include?(@value)
65
65
 
66
66
  @errors << {
67
67
  message: I18n.t("validate_params.invalid_in", param: error_param_name),
@@ -12,13 +12,17 @@ module ValidateParams
12
12
  end
13
13
  end
14
14
 
15
- def self.cast(raw_value, of: String)
16
- case of.to_s
17
- when "Integer"
18
- raw_value.map { |item| Types::Integer.cast(item) }
19
- else
20
- raw_value
21
- end
15
+ def self.cast(raw_value, of: String, reject_blank: false, **)
16
+ value =
17
+ case of.to_s
18
+ when "Integer"
19
+ raw_value.map { |item| Types::Integer.cast(item) }
20
+ else
21
+ raw_value
22
+ end
23
+
24
+ value.reject!(&:blank?) if reject_blank
25
+ value
22
26
  end
23
27
  end
24
28
  end
@@ -20,7 +20,7 @@ module ValidateParams
20
20
  true
21
21
  end
22
22
 
23
- def self.cast(raw_value)
23
+ def self.cast(raw_value, **)
24
24
  return raw_value if raw_value.is_a?(::Date)
25
25
 
26
26
  ::Date.strptime(raw_value.to_s, FORMAT)
@@ -10,7 +10,7 @@ module ValidateParams
10
10
  false
11
11
  end
12
12
 
13
- def self.cast(raw_value)
13
+ def self.cast(raw_value, **)
14
14
  return raw_value if raw_value.is_a?(::Time)
15
15
 
16
16
  Time.at(Integer(raw_value))
@@ -7,7 +7,7 @@ module ValidateParams
7
7
  /\A[-+]?\d+\z/ === value.to_s
8
8
  end
9
9
 
10
- def self.cast(raw_value)
10
+ def self.cast(raw_value, **)
11
11
  raw_value.to_i
12
12
  end
13
13
  end
@@ -3,7 +3,7 @@
3
3
  module ValidateParams
4
4
  class Types
5
5
  class String
6
- def self.cast(raw_value)
6
+ def self.cast(raw_value, **)
7
7
  raw_value.to_s
8
8
  end
9
9
  end
@@ -14,145 +14,121 @@ module ValidateParams
14
14
  extend ::ActiveSupport::Concern
15
15
 
16
16
  included do
17
- before_action :set_params_defaults
18
17
  before_action :perform_validate_params
19
18
  end
20
19
 
21
20
  class_methods do
22
- attr_accessor :params_validations, :method
21
+ attr_reader :params_validations
23
22
 
24
- def param(field, type, options = {}, &block)
25
- @params_validations ||= []
23
+ def validate_params_for(action, options = {}, &block)
24
+ options[:format] ||= :json
25
+ @params_validations ||= {}
26
26
 
27
- if block
28
- param_builder = ParamBuilder.new(field)
29
- @params_validations += yield(param_builder)
30
- else
31
- @params_validations << ParamBuilder.new.param(field, type, options)
32
- end
33
- end
34
-
35
- def validate_params_for(controller_action, options = {}, &block)
36
- @controller_action = controller_action
37
- @response_format = options[:format] || :json
27
+ Array(action).each do |act|
28
+ @params_validations[act] ||= {options: options, validations: []}
38
29
 
39
- yield(self) if block
30
+ yield(ParamBuilder.new(validations: @params_validations[act][:validations])) if block
31
+ end
40
32
  end
41
33
  end
42
34
 
43
35
  def params_validations
44
- self.class.instance_variable_get(:@params_validations) || []
45
- end
46
-
47
- def controller_action
48
- self.class.instance_variable_get(:@controller_action) || nil
49
- end
50
-
51
- def response_format
52
- self.class.instance_variable_get(:@response_format) || nil
36
+ self.class.params_validations || {}
53
37
  end
54
38
 
55
39
  private
56
- def set_params_defaults
57
- params_validations.each do |params_validation|
58
- next unless params_validation[:options].key?(:default)
59
-
60
- if params_validation[:field].is_a?(Hash)
61
- params_validation[:field].each_key do |key|
62
- # Skip in case hash is configured and string is passed
63
- next if params[key].is_a? Hash
64
- next if params.dig(key, params_validation[:field][key])
65
-
66
- value = if params_validation[:options][:default].is_a?(Proc)
67
- params_validation[:options][:default].call
68
- else
69
- params_validation[:options][:default]
70
- end
71
- params.deep_merge!(key => { params_validation[:field][key] => value })
72
- end
73
- else
74
- value = if params_validation[:options][:default].is_a?(Proc)
75
- params_validation[:options][:default].call
76
- else
77
- params_validation[:options][:default]
78
- end
79
-
80
- params[params_validation[:field]] ||= value
81
-
82
- end
83
- end
84
- end
85
-
86
- def cast_param_values
87
- params_validations.each do |params_validation|
88
- if params_validation[:field].is_a?(Hash)
89
- params_validation[:field].each_key do |key|
90
- next unless params[key].is_a?(Hash)
91
-
92
- value = params.dig(key, params_validation[:field][key])
93
- next if value.blank?
94
-
95
- params.deep_merge!(
96
- key => {
97
- params_validation[:field][key] => if params_validation[:type].name == "Array"
98
- Types.const_get(params_validation[:type].name).cast(value,
99
- of: params_validation[:options][:of])
100
- else
101
- Types.const_get(params_validation[:type].name).cast(value)
102
- end
103
- }
104
- )
105
- end
106
- else
107
- value = params[params_validation[:field]]
108
- next if value.blank?
109
-
110
- params[params_validation[:field]] = if params_validation[:type].name == "Array"
111
- Types.const_get(params_validation[:type].name).cast(value, of: params_validation[:options][:of])
112
- else
113
- Types.const_get(params_validation[:type].name).cast(value)
114
- end
115
- end
116
- end
117
- end
118
-
119
40
  def perform_validate_params
120
- return unless controller_action.present? && controller_action == action_name.to_sym
41
+ return unless params_validations.key?(action_name.to_sym)
121
42
 
122
43
  errors = []
44
+ config = params_validations[action_name.to_sym]
123
45
 
124
- params_validations.each do |params_validation|
125
- # Skip in case hash is configured and string is passed
126
- next if params_validation[:field].is_a?(Hash) &&
127
- params[params_validation[:field].keys.first].is_a?(String)
46
+ config[:validations].each do |validation|
47
+ apply_default_values(validation)
128
48
 
129
- parameter_value = if params_validation[:field].is_a? Hash
130
- params.dig(params_validation[:field].keys.first,
131
- params_validation[:field][params_validation[:field].keys.first])
49
+ next if validation[:field].is_a?(Hash) &&
50
+ params[validation[:field].keys.first].is_a?(String)
51
+
52
+ parameter_value = if validation[:field].is_a? Hash
53
+ params.dig(validation[:field].keys.first,
54
+ validation[:field][validation[:field].keys.first])
132
55
  else
133
- params[params_validation[:field]]
56
+ params[validation[:field]]
134
57
  end
135
58
 
136
59
  ParamValidator.call(
137
- type: params_validation[:type],
138
- field: params_validation[:field],
60
+ type: validation[:type],
61
+ field: validation[:field],
139
62
  value: parameter_value,
140
63
  errors: errors,
141
- options: params_validation[:options]
64
+ options: validation[:options]
142
65
  )
143
66
  end
144
67
 
145
68
  if errors.empty?
146
- cast_param_values
69
+ cast_param_values(config[:validations])
147
70
  return
148
71
  end
149
72
 
150
- case response_format
73
+ case config.dig(:options, :format)
151
74
  when :html
152
75
  head :bad_request
153
76
  else
154
77
  render json: { success: false, errors: errors }, status: :bad_request
155
78
  end
156
79
  end
80
+
81
+ def apply_default_values(validation)
82
+ return unless validation[:options].key?(:default)
83
+
84
+ if validation[:field].is_a?(Hash)
85
+ validation[:field].each_key do |key|
86
+ # Skip in case hash is configured and string is passed
87
+ next if hashlike?(params[key])
88
+ next if params.dig(key, validation[:field][key])
89
+
90
+ value = if validation[:options][:default].is_a?(Proc)
91
+ validation[:options][:default].call
92
+ else
93
+ validation[:options][:default]
94
+ end
95
+
96
+ params[key] ||= {}
97
+ params[key][validation[:field][key]] = value
98
+ end
99
+ else
100
+ value = if validation[:options][:default].is_a?(Proc)
101
+ validation[:options][:default].call
102
+ else
103
+ validation[:options][:default]
104
+ end
105
+
106
+ params[validation[:field]] ||= value
107
+ end
108
+ end
109
+
110
+ def cast_param_values(validations)
111
+ validations.each do |validation|
112
+ if validation[:field].is_a?(Hash)
113
+ validation[:field].each_key do |key|
114
+ next unless hashlike?(params[key])
115
+
116
+ value = params.dig(key, validation[:field][key])
117
+ next if value.blank?
118
+
119
+ params[key][validation[:field][key]] = Types.const_get(validation[:type].name).cast(value, **validation.fetch(:options, {}))
120
+ end
121
+ else
122
+ value = params[validation[:field]]
123
+ next if value.blank?
124
+
125
+ params[validation[:field]] = Types.const_get(validation[:type].name).cast(value, **validation.fetch(:options, {}))
126
+ end
127
+ end
128
+ end
129
+
130
+ def hashlike?(obj)
131
+ obj.is_a?(Hash) || obj.is_a?(ActionController::Parameters)
132
+ end
157
133
  end
158
134
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ValidateParams
4
- VERSION = "0.7.0"
4
+ VERSION = "0.8.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: validate-params
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - dcherevatenko