Rails Parameters

Understanding Rails Parameters

Rails parameters let you access data sent by the browser, both via the URL and forms. In this article, we'll cover the basics of parameters, including what they are, how they work, and why they're important. We'll also learn how you can pass parameters in different formats such as arrays and hashes.

9 min read
💡
To serve your users, you have to know what they asked for.

If you are building a dynamic web application, you will need to access and process the data submitted by the user on the server. This data could arrive in a number of ways:

  • the user might upload a photo,
  • write a comment,
  • post a tweet,
  • submit a form, or
  • click a link to an article they want to read.

Regardless of the way by which the data is sent, you want to read this data on the server to do something useful, such as saving that photo, storing the comment / tweet in the database, access the form data, or find the article from the database.

The big question is: How can you access this data on the server, in your Rails application?

The answer is Rails parameters. They let you access the user-submitted data in your Rails application, specifically in your Rails controllers.

💡
Similar to the function parameters, Rails parameters read the data submitted by the user, either in the link or via form submission and make it available in your Rails application in the params object.

The params object serves as a hash-like list of key-value pairs. Each key corresponds to a named input field from the request, and the value contains the data provided by the user for that input.

For example, if your user submits a form with fields named first_name and last_name, the controller can access these fields as follows:

first_name = params[:first_name]
last_name = params[:last_name]

Remember: Since the params object is built from the user input, it's not to be trusted, and you should validate and sanitize before using the data in your application. Rails provides various ways to do this, and we'll explore them all in future posts.

A Simple Analogy to Understand Params

As we learned above, the browser sends a request to the Rails app (on the server), it can include data in the request, which is accessed via the params object. We can illustrate this interaction with a simple analogy. Consider the following code that mimics the browser-server interaction.

# Rails app
def rails(params)
  id = params[:id]
  name = params[:name]
end

# browser sends the parameters to Rails app
rails(id: 5, name: 'learn-to-program')

In this example, the rails function plays the role of your Ruby on Rails application. The browser sends a request to the app by calling this function, passing some data. The Rails app makes this data available in a Hash-like object, which is called, not surprisingly, params, which stands for parameters.

Hope that gave you an conceptual understanding of parameters in Rails.

Different Ways Browsers Send Data to Server

There are two ways in which the browser can send data to the Rails application: via query strings in the URL (GET) and by submitting a form (POST).

Query Strings

  • Include the data in the URL after the ?, e.g. /posts?id=3&user=ak
  • Multiple pieces of key-value pairs are separated by &
  • Typically submitted in a GET request, e.g. clicking a link

Form Submission

  • Contains the data entered into a form by the user.
  • Typically posted in a POST request, e.g. submitting a form

The important thing to know is that Rails doesn’t care about the request type (GET or POST) when accessing the data on the server.

💡
Rails won’t distinguish between the information it receives from query strings and the data from a form submission. It groups all the data into the params hash, which is available in the controller.

Let's inspect both approaches in detail.

Query Strings

Let's assume you've got this route:

Rails.application.routes.draw do
  get 'posts/sample', to: "posts#sample"
end

This route dispatches the request made to the posts/sample URL endpoint to the sample action method on the PostsController class.

When you visit the URL http://localhost:3000/posts/sample?id=3&user=ak, Rails makes the query data available in the following params hash:

{
  "id"         => "3", 
  "user"       => "ak", 
  "controller" => "posts", 
  "action"     => "sample"
}

Note that the params hash also includes the controller and action names. Though you can access them both in your controller, Rails recommends using the controller_name and action_name methods to access these values.

💡
Remember to use the controller_name and action_name methods on the controller to access the controller and action names respectively, instead of reading them directly from the params object.

The params object is in fact, an instance of ActionController::Parameters class, that acts like a hash. We can assume it’s a hash for all practical purposes.

#<ActionController::Parameters {"id"=>"3", "user"=>"ak", "controller"=>"posts", "action"=>"sample"} permitted: false>

The permitted property is related to strong parameters. To learn more about them, check out the following article:

Why You Need Strong Parameters in Rails
In this post, I will explain the Mass Assignment vulnerability and how you can use the Rails strong parameters API to address it.

That's enough about query parameters. Now let's learn the second way the users can send data to the server: by submitting forms.

Form Submission

Consider this form which makes a POST request on the /posts/upload endpoint.

<form action="posts/upload" method="post">
  <div>
    <label for="name">Name:</label>
    <input type="text" id="name" name="user_name">
  </div><br>

  <div>
    <label for="mail">E-mail:</label>
    <input type="email" id="mail" name="user_email">
  </div><br>

  <button type="submit">Submit</button>
</form>

When you fill out and submit the form, the browser sends the data to your Rails application, which creates the following params hash:

{
  "user_name"  => "Akshay", 
  "user_email" => "ak@email.com", 
  "controller" => "posts",
  "action"     => "build"
}

Notice that the keys on the params hash are the same values I used for the name attributes on the form. Rails extracts these name values from the submitted data and adds them as keys to the params hash.

Dynamic Parameters

Parameters can be specified as part of the route declaration itself. If your route URL contains a symbol, Rails will use that symbol name as the key in the params hash.

The following route instructs Rails to map the URL parameter to title.

# routes.rb
get 'posts/lookup/:title', to: 'posts#lookup'

If you visit the posts/lookup/learn-to-code URL, Rails will extract the learn-to-code string and assign it to the title key on the params hash.

# params = { "title" => "learn-to-code" }

class PostsController
  def lookup
    title = params[:title]  # learn-to-code
  end
end

To learn more about the Rails router, check out the following article:

Understanding the Rails Router: Why, What, and How
The router is the entry point of your Rails application. It acts as the gatekeeper for all incoming HTTP requests, inspecting and sending them to a controller action; even filtering and rejecting them if necessary. In this article, we’ll do a deep dive into the Rails Router to understand it better.

More information can be found in my Rails Router handbook.

The Rails Router
Everything you need to know about the incredible routing system in Rails.

Nested Parameters

Instead of sending the name values as keys directly, you can group them under a common key. For example, to group the user_name and user_email under the client key, change the name attribute's value as follows:

<form action="upload" method="post">
  <div>
    <label for="name">Name:</label>
    <input type="text" id="name" name="client[user_name]">
  </div><br>

  <div>
    <label for="mail">E-mail:</label>
    <input type="email" id="mail" name="client[user_email]">
  </div><br>

  <button type="submit">Submit</button>
</form>

This will create the following params hash on the server:

{
  "client": {
    "user_name": "Akshay",
    "user_email": "ak@email.com"
  },
  "controller": "posts",
  "action": "build"
}

Notice that Rails has grouped the user_name and user_email under the client. The nice thing is, when you use the Rails form_with helper, Rails takes care of this for you. For example, consider this form:

<%= form_with model: @book do |form| %>
  <div>
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>
  <div>
    <%= form.label :author %>
    <%= form.text_field :author %>
  </div>
  <%= form.submit %>
<% end %>

It generates the following HTML:

<form action="/books" method="post">
  <div>
    <label for="book_title">Title</label>
    <input type="text" name="book[title]" id="book_title">
  </div>
  
  <div>
    <label for="book_author">Author</label>
    <input type="text" name="book[author]" id="book_author">
  </div>
  
  <input type="submit" name="commit" value="Create Book">
</form>

In the controller, you can access the title and author values as follows:

title = params[:book][:title]
author = params[:book][:author]

It's pretty remarkable how much convenient Rails makes things for you. Recently, I was working on a non-Rails project, and was struck by how much more manual effort was required. Readers, if you're working on Rails apps (and getting paid for it), count your blessings.

Sending JSON

For Rails applications that expose an API, you can receive JSON data from the client to the application. Rails will load it into the params hash, and you can access it in the controllers.

For example, if the client sends the following JSON data:

{ "company": { "name": "Apple", "address": "Cupertino" } }

The params hash will be

{ :company => { "name" => "Apple", "address" => "Cupertino" } }

Pretty convenient.

Sending Arrays and Hashes as Parameters

If you're using named route helpers, you can pass arrays as follows:

get dashboard_path(frameworks: [ "Ruby on Rails", "Laravel" ])

params[:frameworks] # [ "Ruby on Rails", "Laravel" ]

Otherwise, you can pass the following URL and Rails will parse it to build the array parameters:

http://www.example.com?frameworks[]=Ruby+on+Rails&frameworks[]=Laravel

Similarly, you can pass a hash as follows:

get home_path(language: { name: "Ruby", creator: "Matz" })

params[:language][:name]     # "Ruby"
params[:language][:creator]  # "Matz"

The above helper generates the following URL:

http://www.example.com/?language[creator]=Matz&language[name]=Ruby

How to Pass Parameters when Redirecting

When redirecting to another route, you can pass the parameters by passing them as hash parameters to the redirect_to method. For example,

redirect_to controller: 'articles', action: 'show', id: 3, user: 'ak'

The ArticlesController can access the passed values using the params hash as usual. Also remember that you can’t redirect a POST request.

I hope that you have a pretty good understanding of how parameters work in Rails by now. To summarize what we’ve learned so far:

  • All the data sent by the browser is available in the params hash.
  • Rails won't differentiate between the data that comes from a GET request (query string parameters) vs. the data that comes from a POST request (form submission).
  • You can pass nested data using special syntax in your forms and Rails will make it available as a nested Hash.

In the next post in the series, we'll explore about the mass assignment vulnerability and how Rails prevents it with the concept of Strong Parameters. Stay tuned!


That's a wrap. I hope you found this article helpful and you learned something new.

As always, if you have any questions or feedback, didn't understand something, or found a mistake, please leave a comment below or send me an email. I reply to all emails I get from developers, and I look forward to hearing from you.

If you'd like to receive future articles directly in your email, please subscribe to my blog. Your email is respected, never shared, rented, sold or spammed. If you're already a subscriber, thank you.

👉
Building web applications with Rails and Hotwire is something I really enjoy. If you're looking for some help with your Ruby on Rails application — whether you're starting a new project or maintaining a legacy codebase — I can help.

Check out my one-person software studio: https://typeangle.com/ and reach out if you think I'm a good fit for your needs.