A big change coming is how ActionController::Parameters works. ActionController::Parameters is where all of your params come from for your controllers. Calling params used to return a hash, but now will return an object.

Note: this doesn’t affect accessing the keys in the params hash like params[:id]. You can view the PR that implemented this change here: https://github.com/rails/rails/pull/20868

To access the parameters in the object you can add #to_h to the parameters:

params.to_h

If those params aren’t explictly permitted you will be returned a hash with only the permitted parameters. If none are permitted you’ll get an empy hash ({}). This comes in where you may be running #symbolize_keys or #slice on unpermitted params. If you’re accessing params that aren’t being saved to a model/db then you probably aren’t explictly permitting those parameters.

If we look at the #to_h method in ActionController::Parameters we can see it checks if the parameters are permitted before converting them to a hash.

# actionpack/lib/action_controller/metal/strong_parameters.rb
def to_h
  if permitted?
    @parameters.to_h
  else
    slice(*self.class.always_permitted_parameters).permit!.to_h
  end
end

Let’s take an example where we are slicing params to use later. If we have this method that slices params we used to be able to write:

def do_something_with_params
  params.slice(:param_1, :param_2)
end

Which would return:

  { :param_1 => "a", :param_2 => "2" }

But now that will return an ActionController::Parameters object.

Calling #to_h on this would return an empty hash because param_1 and param_2 aren’t permitted.

To get access to the params from ActionController::Parameters you need to first permit the params and then call #to_h on the object. The following returns the same thing as slice did previously.

def do_something_with_params
  params.permit([:param_1, :param_2]).to_h
end

Another way to do this would be to use #to_unsafe_hash if you know the params are not user supplied and are safe:

def do_something_with_params
  params.to_unsafe_h.slice(:param_1, :param_2)
end

By default controller and action parameters are allowed. To explicitly always allow other parameters you can set a configuration option in your application.rb that allows those parameters. Note: this will return the hash with string keys, not symbol keys.

Config option:

  config.always_permitted_parameters = %w( controller action param_1 param_2 )

Calling slice on the parameters:

def do_something_with_params
  params.slice("param_1", "param_2").to_h
end

If you’re not sure when you’ll have time to upgrade it would be a good idea to write some tests for your controllers that access the params. That way when you do upgrade you’ll know to fix the params because your tests will be failing.