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.
-
Query Strings
- Includes the data provided 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
- Includes the data provided in the URL after the
-
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'
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
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
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 theadd
method on thePostsController
class. -
posts/upload
URL to thebuild
method on thePostsController
class.
get 'posts/add', to: 'posts#add'
post 'posts/upload', to: 'posts#build'
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 add
end
end
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>
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
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
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>
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
This prints the following output:
{"client":{"user_name":"Akshay","user_email":"ak@email.com"},"controller":"posts","action":"build"}
name: Akshay
email: ak@email.com
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" } }
The params
hash will be
{ :company => { "name" => "acme", "address" => "123 Carrot Street" } }
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
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'
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.
Top comments (0)