简体   繁体   中英

Declare that the value in strong params must NOT be an array or of a one scalar type

Application accepts a GET request to index products and accepts page param (which should be an integer).

eg http://localhost/products?page=2

Is there a way to ensure that it really is an integer?

Or actually the problem is: Is there a way to ensure that it is NOT an array?

eg http://localhost/products?page[]=2 or http://localhost/products?page[random_key]=2

This will result in an error somewhere in the code.

Now, I know that there is a way to declare it should be an array or a json:

To declare that the value in params must be an array of permitted scalar values, map the key to an empty array:

params.permit(id: [])

And the easiest method I can think of is literally to test if it is NOT an array:

run_the_code unless params[:page].is_a?(Array)
# or
run_the_code if params[:page].is_a?(Integer)

But isn't there a simpler way to use ActionParameters API for example?

eg

params.permit(page: :integer)

The strong parameters API is really only designed to do one thing - slice the parameters down to a whitelist to avoid mass assignment vulnerabilities where a malicous user manages to assign properties they should not have been able to assign. It's not concerned with validating the presence or type of the parameters. That's not its job.

You don't have to worry about it being an array if you just use .permit(:page) since the permitted scalar types doesn't include hashes or arrays. But this really has more to with preventing exploits where a setter method could accept a hash then validating the type of the parameters.

There is also the small fact that formdata pairs (both in the query and request body) are not typed - its all just strings and its really just the backend that converts the parameters into its expected types. params[:page].is_a?(Integer) will thus always be false. Beyond parsing out hashes and arrays Rack doesn't actually have any built in type hinting like for example ?page(i)=2 like you'll find in some frameworks.

Typically in Rails the model handles typecasting the user input and providing validations.

# this is ridiculously overkill
class Paginator
  include ActiveModel::Model
  include ActiveModel::Attributes
  attribute :page, :integer
  attribute :per_page, :integer
  validates :page, numericality: { only_integer: true }
  validates :per_page, numericality: { only_integer: true }

  def to_query
    attributes.symbolize_keys.compact_blank
  end
end
paginator = Paginator.new(params.permit(:page, :per_page))
if paginator.valid?
  Othermodel.paginate(**paginator.to_query)
end

However there are gems that provide alternative approaches such as dry-validations or you can just simply write a method which rejects the parameter if it cannot be coerced into a non-zero integer.

private 

def page
  params.permit(:page).to_i.then{ |n| n.zero? ? nil : n }
end 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM