ruby-on-railsactioncontroller

How can I access the data for the snake object sent through JSON in my params?


Using javascript, I make a fetch post.

const game = {name: this.player, snake: this.snake, score: this.score, apple: this.apple, skull: this.skull, completed: this.completed}
        return fetch("http://localhost:3000/games", {
        method: "POST",
        headers: {
            "Content-Type": "application/json"},
            body: JSON.stringify(game)
        })
        .then(resp => resp.json())
        .then(json => Game.appendHighScores(json));

I access the data via params on the Ruby on Rails end. The data for params[:snake][:body] are supposed to look like "body"=>[{"x"=>16, "y"=>15}, {"x"=>16, "y"=>14}, {"x"=>16, "y"=>15}]}, yet when I type them into the command line, they look like this:

[<ActionController::Parameters {"x"=>16, "y"=>15} permitted: false>, <ActionController::Parameters {"x"=>16, "y"=>14} permitted: false>, <ActionController::Parameters {"x"=>16, "y"=>15} permitted: false>]

It is accessible via indexing, but I get everything along with the data I'm looking for.

I was hoping it would look like the original params when I typed it in

<ActionController::Parameters {"name"=>"Don", "snake"=>{"x"=>16, "y"=>15, "direction"=>"down", "speed"=>0, "directions"=>{"left"=>{"x"=>-1, "y"=>0}, "up"=>{"x"=>0, "y"=>-1}, "right"=>{"x"=>1, "y"=>0}, "down"=>{"x"=>0, "y"=>1}}, "image"=>{}, "body"=>[{"x"=>16, "y"=>15}, {"x"=>16, "y"=>14}, {"x"=>16, "y"=>15}]}, "score"=>0, "apple"=>{"image"=>{}, "x"=>2, "y"=>10}, "skull"=>{"image"=>{}, "x"=>12, "y"=>12}, "completed"=>true, "controller"=>"games", "action"=>"create", "game"=>{"score"=>0, "skull"=>{"image"=>{}, "x"=>12, "y"=>12}, "apple"=>{"image"=>{}, "x"=>2, "y"=>10}, "completed"=>true}} permitted: false>

Anyway to get the params as an array without it looking so messy with ActionController::Parameters inside of the element?


Solution

  • The reason everything is wrapped inside ActionController::Parameters is for your security (mass assignment in particular). You should never trust data send from the internet. This class allows you to permit/whitelist what properties you trust and filter out everything that you don't trust.

    snake_params = params.require(:snake).permit(body: [:x, :y])
    

    You can then convert this into a hash with a simple to_h call, which will drill down into all other nested parameters that are also permitted.

    snake_data = snake_params.to_h
    #=> { "body" => [{"x"=>16, "y"=>15}, {"x"=>16, "y"=>14}, {"x"=>16, "y"=>15}] }
    

    If you'd like to include other attributes as well you can add them to the permit list.

    .permit(:direction, :speed, directions: {left: [:x, :y], up: [:x, :y], ...}, body: [:x, :y])
    

    For more info about permit I suggest checking out the guide Action Controller Overview - 4.5 Strong Parameters.

    If you don't care about permitting certain parameters you can permit everything with permit!.

    Note that you don't have to permit parameters if you extract the values directly. The code below would work perfectly fine without permitting anything.

    body = params[:snake][:body]
    body.each |body_part|
      x = body_part[:x]
      y = body_part[:y]
      // do stuff with x and y
    end