Controller and actions
Rails Controllers are Ruby classes, that store a series of actions. Let's
generate a controller to carry out tasks related operations:
Notice that the above command created multiple files. Let's open the controller
file app/controllers/tasks_controller.rb and add action index to
TasksController:
Now go to the browser and hit
http://localhost:3000/tasks.
We will get a routing error:
Defining routes to map requests to controller actions
Whenever we hit URL on the browser, Rails looks up for that path in the routes
file. If a match is found, then the mapped action in the controller is invoked.
We want to route all requests with URL /tasks to index action of
TasksController.
Open config/routes.rb and add following lines:
Now visit http://localhost:3000/tasks and this
time we should get message This is index action of Tasks controller.
Adding view file
In the above case the content was rendered by the controller itself. We want
views to deliver the final html content.
So let's create file app/views/tasks/index.html.erb:
Open app/views/tasks/index.html.erb file and add the following line:
Open app/controllers/tasks_controller.rb then change the action index:
Now open app/views/layout/application.html.erb and remove the following lines:
Now visit http://localhost:3000/tasks and this
time we should get message List of tasks will appear here.
A gentle introduction to Application controller
All our controllers inherit from ApplicationController. This class is
contained in the file app/controllers/application_controller.rb, which gets
created when we execute the rails new command.
This is what application_controller.rb looks like as of now.
As we can see ApplicationController in turn inherits from
ActionController::Base, which defines a number of helpful methods. We can take
a look at the
API documentation
to understand in detail.
Since ApplicationController is the base controller from which all other
controllers inherit, this controller also act as a gatekeeper. This controller
can check for authentication, authorization, logging etc. We will see all this
in action soon.
Using Rails console to add tasks
Let's open "rails console":
Let's create a Task record and save it in the table:
Let's create one more task and try to save this record:
Calling task.save saves the object in the database. A row is added in tasks
table.
Now we can see all the tasks stored in the database using Task.all:
We will be learning how to display all these tasks in the coming chapters.
Displaying a list of tasks
Now that we have our tasks created, we can pass the list of tasks to our view
file to display it.
First we need to query the list of tasks in our tasks controller and make them
available for our view file like this:
Now we can use the instance variable @tasks to display our list of tasks.
Instance variables from within a controller is directly accessible in the
corresponding view files.
You may have noticed that within the TaskController, we haven't added any require statements to bring in the Task model. This is facilitated by a functionality provided by the Rails framework called autoloading, which eliminates the necessity for explicit module imports. We will explore the intricacies of this feature in the forthcoming chapter.
Replace the content of app/views/tasks/index.html.erb file with the following:
Now when we visit http://localhost:3000/tasks we will see a list of the tasks
that we have created so far.
This approach works if we want Rails to respond only with a view file. But what
if we want a JSON response or an XML response instead? In that case, we can use
Rails MimeResponds, as you will see in the next section.
Rails MimeResponds
In this section, we will be seeing the different ways of responding with data,
by either going through the views or without it.
respond_to is a Rails helper method and it's a way to tell Rails all the
formats the controller action knows about.
If different actions support different formats, then this method helps in
responding differently based on the request.
Let's take an example. No need to type this since we won't be committing this
code:
In the respond_to block, we are specifying what the action needs to reply with
based on the request formats like html, xml or json.
In case of html we are telling rails to go ahead with the default or implicit
route of rendering the view. Whereas for json and xml we are rendering
@tasks in the respective formats as response.
When the format responder is passed with 'json', we are telling it to respond
to requests with the .json extension by serializing to JSON.
We need to pass :html with no arguments in cases where we need to handle
.html requests in the default way by using conventions and views.
If the request is for /tasks.xml then the controller will look for a
/tasks/index.xml.erb view file to render.
If such a view file doesn’t exist then Rails will try to directly render the
resource in the xml format by invoking to_xml.
There is another helper method called respond_with. The respond_with and the
class-level respond_to methods have been moved to the responders gem. Let's
install the responders gem first.
Add this line to the Gemfile:
In respond_with method, we don't need to explicitly tell what needs to be sent
for different mime-types. This makes our work much easier and also this is the
benefit abiding to the DRY principle.
Let's take an example:
Now let's commit changes: