How the Rails params hash works

Uncover the inner workings of Ruby on Rails with our dive into the Params hash—an essential component for handling HTTP requests. From query params to avoiding injection, this article will elevate your understanding of Rails, providing you with the tools to create more secure and efficient web applications.

In Ruby on Rails development, understanding the functionality and role of the params hash is imperative. It serves as a conduit for incoming HTTP request data, connecting user interface elements to the underlying application logic.

In this article, we'll explore the params hash, including its inner workings and practical applications within Rails projects. Additionally, we will discuss the advent of strong parameters, a security measure integrated into Rails to safeguard against malicious user input.

HTTP requests, parameters, and introduction to the params hash in Rails

Applications send and receive a wealth of information each time a user visits a webpage or submits a form. How does this information travel, and where does it end up once it reaches our Rails application? The answer is through Hypertext Transfer Protocol (HTTP) requests and, more specifically, through parameters embedded within these requests.

HTTP is the backbone of data communication on the internet. It defines the format for sending and receiving messages between clients and servers. When you fill out a form on a webpage and hit 'Submit', your browser sends an HTTP request to the server, complete with parameters that contain the data you entered into the form.

In Rails, these incoming parameters find a tidy home in the params hash. This hash is automatically made available in your Rails controllers, giving you easy access to all the parameters that came with the request. It doesn't matter whether the parameters were tucked into the URL, came as part of a form submission, or even if they were sent as part of a JSON request body; Rails bundles them all into the params hash.

Controller methods can take advantage of the params hash to get user-provided values in a clean format:

def create
  @user = User.new(params[:user])
  # Rest of the controller action...
end

The params hash is a versatile tool that Rails developers should be comfortable using. Next, let's dive a little deeper into the params hash and see how we can make the most of it.

Structure of the params hash

To fully wield the power of the params hash, we first need to understand its structure. In Rails, the params hash is not just a plain old Ruby hash. Instead, it's an instance of ActionController::Parameters, a subclass of HashWithIndifferentAccess. This special kind of hash allows you to access its values using either symbols or strings as keys.

Both of the following accesses are valid:

params[:id]
params['id']

The params hash usually contains several key-value pairs. Some of these are added by Rails itself, such as :controller and :action, which tell you which controller and action are processing the request. Any other parameters sent with the request, whether in the URL or the request body, also find their way into the params hash.

When dealing with nested parameters, as you often will when working with forms, the params hash can get a little more complex. For instance, consider a form submission for creating a new user. The form might include fields for a nested profile object. The parameters for this request could look something like this:


{ "controller" => "users", 
  "action" => "create",
  "user" => {
    "username" => "jeffmorhous", 
    "email" => "jeff@example.com",
    "attributes" => {
      "location" => "San Francisco"
    }
  }
}

However, we can still pull out the specific data needed:

params[:user][:username]
params[:user][:attributes][:location]

Having a good handle on the structure of the params hash will make your work in Rails controllers smoother and more efficient. In the next section, we'll look at how Rails treats different kinds of parameters.

URL params vs. query params

It's important to understand the two main types of parameters we'll encounter: URL parameters and query parameters. Although Rails combines both types into the params hash, they originate from different parts of an incoming HTTP request.

URL parameters, also known as path parameters, are embedded directly into the URL. In Rails, you often use these to specify the ID of a resource with which you want to interact. Take the following URL for example: http://www.example.com/users/25. The '25' here is a URL parameter, representing the ID of the user we want to show.

However, query parameters are included after a question mark (?) in the URL and formatted as key-value pairs. These are often used for filtering or sorting data. For instance, http://www.example.com/users?location=San+Francisco includes a query parameter of location, which has the value San+Francisco.

Regardless of whether a parameter comes from the URL or the query string, Rails puts it in the params hash for you to access in your controller. No matter the origin, all parameters end up in the same destination: the Rails params hash. The type of parameter simply changes where the data comes from in the HTTP request and how the data is formatted in the request.

Accessing data in the params hash

One of the main tasks you'll perform with params is extracting data to use within your controller actions. We've already looked at a few examples, so let's recap.

Accessing data from the params hash is as simple as treating it like any other Ruby hash. You can use either string or symbol keys to get the value you want. Let's say we have a params hash like the following: { "controller" => "users", "action" => "show", "id" => "2" }. We could get the 'id' parameter with either of the following lines:

params[:id]       # => '2'
params['id']      # => '2'

Remember the nested parameters example from earlier? Extracting data from a nested structure is a little more involved but follows the same principles. You can chain keys to drill down into the hash:

params[:user][:username]
params[:user][:attributes][:location]

It's important to remember that if you try to access a key that doesn't exist in params, Rails will return nil rather than raising an error. In the next section, we'll talk about strong parameters, a feature that can help protect your application from malicious user input.

Strong parameters

When we're dealing with user input, there's always a risk of malicious activity. The introduction of strong parameters in Rails 4 provided a way to secure our applications by controlling which parameters are permitted in our controllers.

In the past, Rails used a feature called 'attribute protection' to guard against unwanted parameters. However, this feature was model-based, which could lead to bloated models and a lack of flexibility. Strong parameters shifted this protection to the controller, where it makes the most sense. This way, we can handle user input at the point of contact, before it reaches our models.

The key method introduced by strong parameters is require. This method ensures that a specific parameter is present, or an ActionController::ParameterMissing error is raised. We can chain another method, permit, on a require to specify which nested parameters are allowed:

params.require(:user).permit(:username, :email, attributes: [:location])

In this example, we're saying that the :user parameter must be present. Within :user, only the :username, :email, and :attributes keys are allowed. Furthermore, within :attributes, only :location is permitted.

It's common practice to put this params.require call into a private method, and then use the result of calling this method to access params. The method might look like this:

private

  def user_params
    params.require(:user).permit(:username, :email, attributes: [:location])
  end

Meanwhile, instead of using params to access the params hash, you could instead use user_params:

user_params[:user][:username]
user_params[:user][:attributes][:location]

Strong parameters give us the ability to define what's allowed and what's not in a clear and concise way. This makes it an essential part of managing the params hash in a secure Rails application.

Conclusion

As we've seen throughout this exploration, the params hash is a powerful and flexible feature in Rails. It provides a simple interface for accessing data from incoming HTTP requests, whether it's URL parameters, form data, or even API request bodies. By understanding how parameters work, you can handle user input in a secure and efficient manner.

The advent of strong parameters added a layer of security to this process, ensuring that Rails applications are protected from unwanted data manipulation. Through the appropriate use of require and permit methods, we can filter out unwanted parameters and maintain the integrity of our data.

While the params hash might seem like just another part of Rails, it plays a key role in making your application functional and secure. Deepening your understanding of it empowers you to make full use of its capabilities in your Rails applications.

What to do next:
  1. Try Honeybadger for FREE
    Honeybadger helps you find and fix errors before your users can even report them. Get set up in minutes and check monitoring off your to-do list.
    Start free trial
    Easy 5-minute setup — No credit card required
  2. Get the Honeybadger newsletter
    Each month we share news, best practices, and stories from the DevOps & monitoring community—exclusively for developers like you.
    author photo

    Jeffery Morhous

    Jeff is a Software Engineer working in healtcare technology using Ruby on Rails, React, and plenty more tools. He loves making things that make life more interesting and learning as much he can on the way. In his spare time, he loves to play guitar, hike, and tinker with cars.

    More articles by Jeffery Morhous
    Stop wasting time manually checking logs for errors!

    Try the only application health monitoring tool that allows you to track application errors, uptime, and cron jobs in one simple platform.

    • Know when critical errors occur, and which customers are affected.
    • Respond instantly when your systems go down.
    • Improve the health of your systems over time.
    • Fix problems before your customers can report them!

    As developers ourselves, we hated wasting time tracking down errors—so we built the system we always wanted.

    Honeybadger tracks everything you need and nothing you don't, creating one simple solution to keep your application running and error free so you can do what you do best—release new code. Try it free and see for yourself.

    Start free trial
    Simple 5-minute setup — No credit card required

    Learn more

    "We've looked at a lot of error management systems. Honeybadger is head and shoulders above the rest and somehow gets better with every new release."
    — Michael Smith, Cofounder & CTO of YvesBlue

    Honeybadger is trusted by top companies like:

    “Everyone is in love with Honeybadger ... the UI is spot on.”
    Molly Struve, Sr. Site Reliability Engineer, Netflix
    Start free trial
    Are you using Sentry, Rollbar, Bugsnag, or Airbrake for your monitoring? Honeybadger includes error tracking with a whole suite of amazing monitoring tools — all for probably less than you're paying now. Discover why so many companies are switching to Honeybadger here.
    Start free trial