Getting paranoid about your Rails application params? Try paramoid!
Paramoid is an extension for Rails Strong Parameters that allows to sanitize complex params structures with a super cool DSL, supporting:
- Required params and default values
- A simplified nested structures management
- Conditional sanitization, based on user auth, role or custom logic
- Renaming and remapping parameter names
Add the gem to your Gemfile
gem 'paramoid'
and run the bundle install
command.
Declare a class extending Paramoid::Base
.
class PersonParamsSanitizer < Paramoid::Base
# @param [User] user
def initialize(user = nil)
params! :first_name, :last_name
group! :address_attributes do
params! :id, :road, :town, :state, :zip_code, :country
end
end
end
Then use it in your controller:
class PeopleController < ApplicationController
def create
@person = Person.create!(person_params)
end
private
def person_params
# The name is automatically inferred by the controller name
sanitize_params!
# Or you can instantiate a custom one
# You can pass the current user or nil
# CustomPersonParamsSanitizer.new(current_user).sanitize(params)
end
end
Paramoid is based on Rails Strong Parameters and it's inheriting its behaviour.
param!
is used to permit a single scalar parameter.param! :name
is equivalent ofparams.permit(:name, ...)
params!
is just a shortcut to sanitize in mass a list of parameters having the same optionsgroup!
is used to sanitize objects or arrays, likeparams.permit(my_key: [:list, :of, :keys])
array!
is an alias ofgroup!
and it's added for readability: in Strong Parameters,params.permit(name: [:some_key])
accepts both a single object or an array of objects, and this is preserved here.
So the previous example:
class PersonParamsSanitizer < Paramoid::Base
# @param [User] user
def initialize(user = nil)
params! :first_name, :last_name
group! :address_attributes do
params! :id, :road, :town, :state, :zip_code, :country
end
end
end
Is equivalent to:
params.permit(:first_name, :last_name, address_attributes: [:id, :road, :town, :state, :zip_code, :country])
Declaring a parameter as required, will raise a ActionController::ParameterMissing
error if that parameter is not passed by to the controller. This also works with nested structures.
class UserParamsSanitizer < Paramoid::Base
def initialize(user = nil)
params! :first_name, :last_name, required: true
group! :contact_attributes do
param! :phone, required: true
end
end
end
You can declare a default value to a certain parameter. That value is assigned only if that value is not passed in the parameters.
Example:
class PostParamsSanitizer < Paramoid::Base
def initialize(user = nil)
param! :status, default: 'draft'
param! :approved, default: false
end
end
Input:
<ActionController::Parameters {"status"=>"published","another_parameter"=>"this will be filtered out"} permitted: false>
Output:
<ActionController::Parameters {"status"=>"published","approved":false} permitted: true>
You can also remap the name of a parameter.
class PostParamsSanitizer < Paramoid::Base
def initialize(user = nil)
param! :status, as: :state
end
end
Input:
<ActionController::Parameters {"status"=>"draft","another_parameter"=>"this will be filtered out"} permitted: false>
Output:
<ActionController::Parameters {"state"=>"draft"} permitted: true>
By using the reference of the current_user in the constructor, you can permit certain parameters based on a specific condition.
Example:
class PostParamsSanitizer < Paramoid::Base
def initialize(user = nil)
params! :first_name, :last_name
param! :published if user&.admin?
end
end
You can also use the sanitizer DSL inline directly in your controller:
class PeopleController < ApplicationController
def create
@person = Person.create!(person_params)
end
private
def person_params
sanitize_params! do
params! :first_name, :last_name, required: true
end
end
end
class PersonParamsSanitizer < Paramoid::Base
# @param [User] user
def initialize(user = nil)
params! :first_name, :last_name, :gender
param! :current_user_id, required: true
param! :an_object_filtered
param! :an_array_filtered
array! :an_array_unfiltered
param! :role if user&.admin?
default! :some_default, 1
group! :contact, as: :contact_attributes do
params! :id, :first_name, :last_name, :birth_date, :birth_place, :phone, :role, :fiscal_code
end
end
end
- Params type checking and regexp-based validations
Paramoid is maintained by mònade srl.
We <3 open source software. Contact us for your next project!