Strong params with a JS frontend and a Rails backend

Sascha Kala
3 min readDec 28, 2020
A screenshot of my games_controller and strong params method

I recently completed my JavaScript portfolio project at Flatiron. Coming from a purely Ruby / Rails background, this was my first ever time truly implementing JavaScript.

(I went in determined to fall in love with JS the same way I had with Ruby many months ago, and I think it’s safe to say that I did. Anything’s possible. It blows my mind.)

The thing I struggled with most was integrating the front endPOST request with my backend create method: specifically whitelisting my strong params. Coming from Rails, I had gotten used to Form Helpers taking care of the necessary behind the scenes legwork for me.

In a typical Rails app, a basic strong_params controller method looks like this:

privatedef model_params
params.require(:model_name).permit(:attribute_1, :attribute_2)
end

When data is submitted using form_with or form_for, both of which are bound directly to the ActiveRecord models they were created for, the params that come in already contain the required model_name param above (because the form knows which model it belongs to).

But, when submitting a form from JS, this Rails magic is noticeably absent.

The app that I created is a (colorful) version of my favorite old school game: Brick. On GAME OVER, it allows the player to save their high score to the scoreboard. A User has_many games, and a Game belongs_to a user.

A screenshot of the Brick game app I created. Playing canvas is on the left side of the screen and scoreboard is on the right
JavaScript Brick app I created for my JS portfolio project

My games_controller strong param method was as follows:

def game_params
params.require(:game).permit(:score, :user_name)
end

And I created a custom setter/getter for user_name so that a user could be instantiated alongside their score.

But…my games weren’t saving.

After playing around in pry it became clear that the params were coming in without the required :game param. They looked like this:

Screenshot of params coming through from original bodyData object.

Rails was able to guess that :score (an attribute of the Game model), belonged to :game, and so was permitting it into strong params. But user_name was being left out and so games were unable to save.

The data I was sending in from my front end was as follows:

I collected the data (score and name) into constants from their respective places on the page and passed them to the postFetch function.

function formHandler(e) {
e.preventDefault()
const formScorePhrase = document.getElementById(“score”).innerText
const formScore = parseInt(formScorePhrase.replace(“Score: “, “”))
const formName = document.getElementById(“name”).value
postFetch(formScore, formName)

}

I created a bodyData object to hold both pieces of data and passed that in to the body: attribute of the fetch function.

function postFetch(score, user_name){
const bodyData = {score, user_name}
fetch(endPoint, {
method: “POST”,
headers: {“Content-Type”: “application/json”},
body: JSON.stringify(bodyData),
})

Turns out, all I needed to do to satisfy my params requirement was create a nested bodyData object that placed {score, user_name} as the value of a game: key.

function postFetch(score, user_name){
const bodyData =
{game:
{score, user_name}
}

Now the params coming into my backend upon postFetch look like this:

Screenshot of params coming through from updated bodyData object.

My strong_params requirement is satisfied and scores will save!

--

--

Sascha Kala

Software engineer and they/them tech femme; artist // digital creator