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:
We will be updating the application.html.erb
file in an upcoming chapter.
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: