DEV Community

Akshay Khot
Akshay Khot

Posted on • Originally published at akshaykhot.com

Understanding Rails Parameters

If you are building a dynamic web application, you will need to access the user-submitted data on the server. Maybe the user uploaded a photo, wrote a comment, posted a tweet, or clicked a link that includes the id of the article they want to read. How do you access this data on the back-end?

That's where parameters enter into the picture. This article explains everything you need to know to understand Rails parameters.

There are two ways to get data from the front-end to the back-end.

  1. Query Strings
    • Include the data in the URL after the ?, e.g. blog.com/posts?id=3&user=ak
    • Data consists of key-value pairs separated by &
    • Typically submitted in a GET request, e.g. clicking a link
  2. Form Submission
    • Contains the data entered into a form by the user.
    • Typically posted in a POST request, e.g. submitting a form

The good thing is that Rails doesn't care about the request type (GET or POST) when accessing the data on the server. It won't distinguish between the information 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.

Query Strings

The following route in the routes.rb file routes the /posts/sample URL to the sample method on the PostsController class.

get 'posts/sample', to: 'posts#sample'
Enter fullscreen mode Exit fullscreen mode

Here's the PostsController#sample method. To keep things simple, I am rendering plain text without using a view template.

class PostsController < ApplicationController
  def sample
    render plain: "#{params} \n\nid: #{params[:id]} \nuser: #{params[:user]}"
  end
end
Enter fullscreen mode Exit fullscreen mode

Now, when I go to the URL http://localhost:3000/posts/sample?id=3&user=ak, it renders:

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

id: 3 
user: ak
Enter fullscreen mode Exit fullscreen mode

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

Form Submission

The following route in the routes.rb file routes the

  • posts/add URL to the add method on the PostsController class.
  • posts/upload URL to the build method on the PostsController class.
get 'posts/add', to: 'posts#add'
post 'posts/upload', to: 'posts#build'
Enter fullscreen mode Exit fullscreen mode

Here's the PostsController#add method, which renders the add.html.erb view. With the Rails conventions, it will render the add.html.erb view template.

class PostsController < ApplicationController
  def sample
  end
end
Enter fullscreen mode Exit fullscreen mode

Let's create a simple form in our add.html.erb template. When submitted, this form will make a POST request on the /posts/upload endpoint.

<form action="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>
Enter fullscreen mode Exit fullscreen mode

To handle this Post request, let's add the build method on the PostsController. Again, I am simply rendering the data as plain text, without the view to keep things simple. I have also disabled the Rails authenticity_token security measure to avoid adding unnecessary complexity to the example (don't do this in a real application).

skip_before_action :verify_authenticity_token, only: :build

def build
  render plain: "#{params} \n\nname: #{params[:user_name]} \nemail: #{params[:user_email]}"
end
Enter fullscreen mode Exit fullscreen mode

Now, when you enter some data in the form and click the Submit button, you are greeted with:

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

name: Akshay 
email: ak@email.com
Enter fullscreen mode Exit fullscreen mode

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

Instead of sending the name values as keys directly, you can group them under a common key in the name attribute.

<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>
Enter fullscreen mode Exit fullscreen mode

Let's modify the build method to access the nested parameters:

def build
    render plain: "#{params.to_json} \n\nname: #{params[:client][:user_name]} \nemail: #{params[:client][:user_email]}"
end
Enter fullscreen mode Exit fullscreen mode

This prints the following output:

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

name: Akshay 
email: ak@email.com
Enter fullscreen mode Exit fullscreen mode

Notice that Rails has grouped the user_name and user_email under the client.

Sending JSON

For a rails API, you can send JSON data from the client. Rails will load it into the params hash, and you can access it in the controllers. For example, if you send the following JSON data:

{ "company": { "name": "acme", "address": "123 Carrot Street" } }
Enter fullscreen mode Exit fullscreen mode

The params hash will be

{ :company => { "name" => "acme", "address" => "123 Carrot Street" } }
Enter fullscreen mode Exit fullscreen mode

Dynamic Parameters

If your route URL contains a symbol, Rails will use that symbol name as the key in the params hash. In the following example, the route instructs Rails to map the URL parameter to title.

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

# posts_controller
def lookup
  render plain: "#{params} \n\ntitle: #{params[:title]}"
end

# browser output
{"controller"=>"posts", "action"=>"lookup", "title"=>"rails"} 

title: rails
Enter fullscreen mode Exit fullscreen mode

Passing 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'
Enter fullscreen mode Exit fullscreen mode

The ArticlesController can access the passed values using the params hash as usual. However, an important thing to note is 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:

  • Rails doesn'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), and
  • All the data is available in the params hash.

In the next post, we will look at a common problem in software, known as Mass Assignment Vulnerability, and how Rails helps us tackle it by providing strong parameters.

Discussion (0)