Giter Club home page Giter Club logo

stronger_parameters's Introduction

stronger_parameters

CI

This is an extension of strong_parameters with added type checking and conversion.

Simple types

You can specify simple types like this:

params.permit(
  id: Parameters.id,
  name: Parameters.string
)

Arrays

You can specify arrays like this:

params.permit(
  id: Parameters.array(Parameters.id)
)

This will allow an array of id parameters that all are IDs (integer less than 2**31, greater than 0) and convert to Fixnum ('2' --> 2).

Empty array -> nil

Rails converts empty arrays to nil, so often Parameters.array | Parameters.nil is needed.

Allowing nils

It can be convenient to allow nil for all attributes since ActiveRecord converts it to false/0. ActionController::Parameters.allow_nil_for_everything = true

Rejecting nils

You can reject a request that fails to supply certain parameters by marking them as required with the .required operator:

params.permit(
  name: Parameters.string.required, # will not accept a nil or a non-String
  email: Parameters.string          # optional, may be omitted
)

This also works in conjunction with the & and | constraints. For example, to express that a uid must be either a string or a number:

params.permit(
  uid: (Parameters.string | Parameters.integer).required
)

Nested Parameters

params.permit(
  name: Parameters.string,
  emails: Parameters.array(Parameters.string),
  friends: Parameters.array(
    Parameters.map(
      name: Parameters.string,
      family: Parameters.map(
        name: Parameters.string
      ),
      hobbies: Parameters.array(Parameters.string)
    )
  )
)

This will allow parameters like this:

{
  "name": "Mick",
  "emails": ["[email protected]", "[email protected]"],
  "friends": [
    {"name": "Morten", "family": {"name": "Primdahl"}, "hobbies": ["work", "art"]},
    {"name": "Eric", "family": {"name": "Chapweske"}, "hobbies": ["boating", "whiskey"]}
  ]
}

ActiveModel Nested Attributes

params.require(:author).permit(
  name: Parameters.string,
  books_attributes: Parameters.array(
    Parameters.map(
      title: Parameters.string,
      id: Parameters.id,
      _destroy: Parameters.boolean
    )
  )
)

This will allow parameters like this:

{
  "author": {
    "name": "Eric Chapweske",
    "books_attributes": [
      {"title": "Boatin' and Drinkin'", "id": 234, "_destroy": true},
      {"title": "Advanced Boatin' and Drinkin'", "id": 567}
    ]
  }
}

Combining Requirements

If you want to permit a parameter to be one of multiple types, you can use the | operator:

params.require(:ticket).permit(
  status: Parameters.id | Parameters.enum('open', 'closed')
)

This will allow these parameter sets:

{
  "ticket": {
    "status": 123
  }
}
{
  "ticket": {
    "status": "open"
  }
}

You can use the & operator to apply further restrictions on the type:

params.require(:user).permit(
  age: Parameters.integer & Parameters.gte(0)
)

This requires the parameter to be an integer greater than or equal to 0.

Combining Requirements in Arrays

You can also use the | and & operators in arrays:

params.require(:group).permit(
  users: Parameters.array(Parameters.id | Parameters.string)
)

This will permit these parameters:

{
  "group": {
    "users": [123, "[email protected]", 345, 676, "[email protected]"]
  }
}

Rollout in log-only mode

Just want to log violations in production:

# config/environments/production.rb
ActionController::Parameters.action_on_invalid_parameters = :log

Controller support

Include PermittedParameters into a controller to force the developer to explicitly permit params for every action.

Examples:

class TestController < ApplicationController
  include StrongerParameters::ControllerSupport::PermittedParameters

  permitted_parameters :all, locale: Parameters.string # permit :locale in all actions for this controller

  permitted_parameters :show, id: Parameters.integer
  def show
  end

  permitted_parameters :create, topic: { forum: { id: Parameters.integer } }
  def create
  end

  permitted_parameters :index, {} # no parameters permitted
  def index
  end

  permitted_parameters :update, :skip # use when migrating old controllers/actions
  def update
  end
end

Log only mode for invalid parameters

To only log invalid (not unpermitted) parameters during rollout of stronger_parameters:

class MyController < ApplicationController
  log_invalid_parameters! if Rails.env.production? # Still want other environments and controllers to raise

  permitted_parameters :update, user: { name: Parameters.string }
  def update
  end
end

Notifying users about unpermitted params

Add headers to all requests that have unpermitted params (does not log invalid):

# config/application.rb
config.stronger_parameters_violation_header = 'X-StrongerParameters-API-Warn'
curl -I 'http://localhost/api/users/1.json' -X POST -d '{ "user": { "id": 1 } }'
=> HTTP/1.1 200 OK
=> ...
=> X-StrongerParameters-API-Warn: Removed restricted keys ["user.id"] from parameters

Types

Syntax (Simplified) Definition
Parameters.string value.is_a?(String)
Parameters.integer value.is_a?(Fixnum) or '-1'
Parameters.float value.is_a?(Float) or '-1.2'
Parameters.date value.is_a?(Date) or '2014-05-13' or '13.05.2014'
Parameters.date_iso8601 value is a date that conforms to ISO8601: '2014-05-13'
Parameters.time value.is_a?(Time) or '2014-05-13' or '2015-03-31 14:34:56 +0000'
Parameters.time_iso8601 value is a time that conforms to ISO8601: '2014-05-13' or '2015-03-31T14:34:56Z'
Parameters.datetime value.is_a?(DateTime) or '2014-05-13' or '2015-03-31T14:34:56Z'
Parameters.datetime_iso8601 value is a date that conforms to ISO8601: '2014-05-13' or '2015-03-31T14:34:56Z'
Parameters.regexp(/foo/) value =~ regexp
Parameters.enum('asc', 'desc') ['asc', 'desc'].include?(value)
Parameters.lt(10) value < 10
Parameters.lte(10) value <= 10
Parameters.gt(0) value > 0
Parameters.gte(0) value >= 0
Parameters.integer32 Parameters.integer & Parameters.lt(2 ** 31) & Parameters.gte(-2 ** 31)
Parameters.integer64 Parameters.integer & Parameters.lt(2 ** 63) & Parameters.gte(-2 ** 63)
Parameters.id Parameters.integer & Parameters.lt(2 ** 31) & Parameters.gte(0)
Parameters.bigid Parameters.integer & Parameters.lt(2 ** 63) & Parameters.gte(0)
Parameters.uid Parameters.integer & Parameters.lt(2 ** 32) & Parameters.gte(0)
Parameters.ubigid Parameters.integer & Parameters.lt(2 ** 64) & Parameters.gte(0)
Parameters.boolean Parameters.enum(true, false, 'true', 'false', 1, 0)
Parameters.nil value is nil
Parameters.nil_string value is nil, '', 'undefined'
Parameters.file File, StringIO, Rack::Test::UploadedFile, ActionDispatch::Http::UploadedFile or subclasses
Parameters.decimal(8,2) value is a String, Integer or Float with a precision of 9 and scale of 2
Parameters.hex value is a String that matches the hexadecimal format
Parameters.ulid value is a String of length 26 with only Crockford Base32 symbols

Development

Releasing a new version

git checkout master && git fetch origin && git reset --hard origin/master
bundle exec rake bump:<patch|minor|major>
bundle exec rake release

github action will release a new version to rubygems.org

stronger_parameters's People

Contributors

alisonacuna avatar amireh avatar arthurnn avatar bartoszkopinski avatar bdewater avatar bquorning avatar bwillis avatar dadah89 avatar fwilkens avatar gencer avatar grosser avatar ianubhav avatar isaacsu avatar jobertabma avatar kintner avatar klobuczek avatar libo avatar lukkry avatar pschambacher avatar sandlerr avatar shanethmoore avatar skateman avatar staugaard avatar swanjr avatar zenspider avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.