How does Params work in Sinatra?
Tags: ruby, rails, beginners, sinatra
Published: 2021-07-20 16:19:29

When working with Sinatra or Rails, you will most likely encounter something called **params**. It is short for *parameters* and is often seen inside route (request handler) blocks of controllers that handle HTTP requests such as GET or POST:
```ruby
# songs_controller.rb
patch "/songs:id" do 
    song = Song.find(params[:id])
    attrs_to_update = params.select{|k,v| ["name", "genre"].include?(k)}
    song.update(attrs_to_update)
    song.to_json
  end 
```

At first, `params` may seem a bit magical as it somehow automatically contains the data included in requests:
```ruby
params = {
   "name" => "some_name",
   "genre" => "some_genre",
   "id" => "some_id"
}
```

So what is this magic called `params`?

**Params** is a method inherited from `ActionController::Base` that accesses the parameters passed from a request and returns a hash that encapsulates the parameters. It can access those parameters in one of two main ways: through the *request body* or through the *request path*. 

###Accessing Parameters Through the Request Body 
Oftentimes, a web application will have an HTML form that can be filled by the user. On submission, the form would typically generate a POST request that contains the values of the user's inputs along with the names of the inputs inside a body object:
```js
// A POST request that contains a body object
const newSong = {
   name: "Fly Me to the Moon",
   genre: "Jazz"
}

const configObj = {
   method: "POST",
   headers: {
      "Content-Type": "applications/json",
      "Accept": "applications/json"
   },
   body: JSON.stringify(newSong)
};

fetch("http://example.com/songs", configObj);
```

When this request is received by the controller, it will look at the body object sent with the request and add parameters accordingly to the `params` hash:
```ruby
params = {
   "name" => "Fly Me to the Moon",
   "genre" => "Jazz"
}
```
> Note: The keys and values of a `params` hash will always be of the string type. However, the hash keys can be accessed indiscriminately as strings or symbols since `params` doesn't actually return a hash, but it returns something similar called `Sinatra::IndifferentHash`.

###Accessing Parameters Through the Request Path 
The other main way to access request parameters is through the request path, or simply the URL. When the controller receives the request, it will look at the attributes within the request URL and add parameters to the `params` hash based on those attributes. This allows us to design routes more dynamically instead of hard-coding each route individually. There are two types of parameters that can be accessed based on the URL attributes: *query* and *route* parameters.

####Query Parameters
Query parameters are parameters included after the `?` in the request URL as shown below:
```js
// A GET request with query parameters in the URL
fetch(http://www.example.com/songs?name=foo&genre=pop)
```

Such parameters are often used when we want to filter our search results (AKA what a GET request returns) by some queries and restrictions. For this reason, query parameters are considered optional and not explicitly included in the route path:
```ruby
# songs_controller.rb
get "/songs" do
   ... 
end
```

However, the `params` hash will still include the query parameters found in the request path:
```ruby
params = {
   "name" => "foo",
   "genre" => "pop"
}
```

####Route Parameters
Unlike query parameters, route parameters must be named within the route path for them to be accessible via the `params` hash:
```ruby
# songs_controller.rb
get "/songs/:id" do
   ... 
end
```

The controller would then recognize the route parameter in the request path by the placement of the parameter value within the URL:
```js
fetch("http://www.example.com/songs/3")
```

... and add it to the `params` hash:
```ruby
params = { "id" => "3" }
```

Route parameters can also be combined with query parameters:
```js
fetch("http://www.example.com/songs/3?name=foo&genre=pop")
```

... for an even more customizable `params` hash:
```ruby
params = {
   "id" => "3",
   "name" => "foo",
   "genre" => "pop"
}
```

###Conclusion
While the magic of `params` is often unquestioned and left to wonders, its behavior under-the-hood is actually straightforward to grasp. To summarize, `params` is an inherited method that returns a hash that contains parameters passed by a request through its body or through its URL. Overall, understanding this behavior will (hopefully) make your life easier by equipping you with the ability to control the structure of the `params` hash as well as build routes more effectively.

Params can also access other types of parameters such as splat (wildcard), regular expression (regex), and optional parameters. To learn more about them, you can refer to the first resource down below.

Happy coding!

###Resources
- [Sinatra README](http://sinatrarb.com/intro.html)
- [How params work on Sinatra](https://medium.com/@ingridf/how-params-work-on-sinatra-6aef2d138cf9)
- [Understanding Params In Sinatra](https://dev.to/anglam/understanding-params-in-sinatra-20oo)
- [How Params Works in Rails](https://flatironschool.com/blog/how-params-works-in-rails)