Create typed parameter class using strong parameter in rails. You can cleanup parameter code for permit in your controller and convert it to the type you want. You can get your OpenAPI JSON for parameter schemas.
Add this line to your application's Gemfile:
gem 'typed-parameter'And then execute:
$ bundle install
Or install it yourself as:
$ gem install typed-parameter
class UserCreateParams < TypedParameter::Base
field :name, String
field :age, Integer
field :email, String
end
-----------------------------------------------
############
## before ##
############
# method for params
def user_create_params
params.permit(:name, :age, :email)
end
# in action
def create
raise UserAgeTooYoung if user_create_params[:age].to_i < 20
# You need to convert your parameter type
end
############
## after ###
############
# method for params
def user_create_params
UserCreateParams.permit(params)
end
# in action
def create
raise UserAgeTooYoung if user_create_params[:age] < 20
# paramters are converted as your type
endclass CustomParameter < TypedParameter::Base
field :string_field, String
field :integer_field, Integer
field :float_field, Float
field :date_field, Date
field :datetime_field, DateTime
field :boolean_field, Boolean
end
############
## before ##
############
def custom_params
params.permit(
:string_field, # => is_a? String
:integer_field, # => is_a? String. You need to &:to_i
:fload_field, # => is_a? String. You need to &:to_f
:date_field, # => is_a? String. You need to &:to_date
:datetime_field # => is_a? String. You need to &:to_datetime
:boolean_field # => is_a? Boolean. If paramter is string (like "false") then String
)
end
############
## after ##
############
def custom_params
CustomParamter.permit(params)
end
custom_params[:string_field] # => is_a? String
custom_params[:integer_field] # => is_a? Integer
custom_params[:float_field] # => is_a? Float
custom_params[:date_field] # => is_a? Date
custom_params[:datetime_field] # => is_a? DateTime
custom_params[:boolean] # => is_a? Boolean, If parameter is string (like "false", "true" "False", "True") then convert true or falseclass EnumAndRequiredParameter < TypedParameter::base
field :enum_field, Integer, enum: [10, 20, 30, 40]
field :required_field, String, required: true
end
def enum_and_required_params
EnumAndRequiredParameter.permit(params)
end
# If params[:enum_field] has 25 ( not in 10, 20, 30, 40)
# => ArgumentError, "enum_field must be in 10, 20, 30, 40"
# if params[:required_field] is Nil
# => ArgumentError, "required_field is required"class ParentParameter < TypedParameter::Base
field :name, String
field :integers, [Integer]
field :child, ChildParameter
field :childs, [ChildParamter]
end
class ChildParameter < TypedParameter::Base
field :name, String
end
example_params = {
name: "Name",
integers: ['1','2','3','4'],
child: { name: "child" },
childs: [
{ name: "child1", age: "10" },
{ name: "child2", age: "12" },
{ name: "child3", age: "15" }
]
}
def parent_and_childs_params
ParentParameter.permit(example_params)
end
# Result
{
name: "Name",
integers: [1,2,3,4],
child: { name: "child" },
childs: [
{ name: "child1" },
{ name: "child2" },
{ name: "child3" }
]
}If You want to use your custom type like Email, just create two file.
- your type file. like "Email"
- yout type constant. like "EmailConstrant"
class Email
def initialize(value)
@email = value
end
end
class EmailConstrant
class << self
EMAIL_REGREX = //
# using convert value to your type
def value(value)
raise ArgumentError unless EMAIL_REGREX.match? value
Email.new(value)
end
end
end
class EmailSwaggerType
class << self
def value
{ type: :string }
end
end
end
# Register your type to typed-parameter when application initialize.
TypedParameter::ParameterTypes.register Email
TypedParameter::Constants.register :Email, EmailConstrant
TypedParameter::Swagger::Types.register :Email, EmailSwaggerTypeYou can use parameter class by block
class BlockParameter < TypedParameter::Base
field :some_object, Object do |i|
i.field :name, String
i.field :type, String
end
field :other_hash_list, [Hash] do |i|
i.field :index, Integer
i.field :value, Float
end
endWith Rswag(https://github.com/rswag/rswag), you can swaggerize your parameter types.
class SwaggerParameter < TypedParameter::Base
field :string, String, enum: ["one", "two"], description: "String Field"
field :integer, Integer, description: "Integer Field"
field :ref_field, SwaggerRefParameter
end
class SwaggerRefParameter < TypedParameter::Base
field :string, String, description: "Ref String Field"
end
SwaggerParameter.swagger_properties
# =>
# {
# string: { type: :string, enum: ["one", "two" ], description: "String Field" },
# integer: { type: :integer, description: "Integer Field" },
# ref_field: { "$ref": "#/components/schemas/SwaggerRefParamter" }
# }
#
# Add Components in your swagger
# in swagger_helper
components = TypedParameter::Swagger::ComponentGenerator.generate_all!
config.swagger_docs = {
'v1/swagger.yaml' => {
openapi: '3.0.1',
# ...,
components: {
schemas: {
**components
}
}
#...
}
}...
After checking out the repo, run bin/setup to install dependencies. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/tranquilthink/typed-parameter.