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
endThen 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
endParamoid is based on Rails Strong Parameters and it's inheriting its behaviour.
param!is used to permit a single scalar parameter.param! :nameis 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
endIs 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
endYou 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
endInput:
<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
endInput:
<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
endYou 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
endclass 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!
