Controllers and Routing
In this guide you will learn about controllers and how they fit into the Rails framework. We will cover very basic concepts, and further explanations will be linked in specific guides linked below, or can be found in Rails's official Action Controller guide here.
What is a Controller?
A controller mediates the communication between views and models in order to serve the right resources for your application to display. The model should not know how to represent itself in the view, and the view should not know how resources should be acquired from the models. The two parties both communicate with the controller, which knows which models to extract from or write to, and then renders the correct data into the correct views. An application without controllers would have a very limited amount of flexibility of managing its resources.
CRUD Actions
CRUD stands for Create, Read, Update, and Destroy. These are the four basic functions that interface with persistent storage, such as a database. Rails models are essentially wrappers to tables in a database, and it's the controller's job to select the correct action to use for a particular model after receiving a request.
Rails defines several default actions for a particular resource, and they are as follows:
class UsersController < ApplicationController
def index
# Gets a list of all users
end
def new
# Shows how to create a new user (think of something like a sign up form)
end
def create
# Creates a new user and adds it to the database
end
def show
# Shows a particular user's information
end
def edit
# Shows how to edit a particular user (think of an edit form)
end
def update
# Updates a users attributes in the database
end
def destroy
# Removes a user from the database
end
end
These are obviously not implemented, but when you declare something like a User to be a resource in your application, Rails will expect the UsersController to have these methods.
A Note on Naming
Rails follows a central paradigm called "Convention over Configuration", which basically means that Rails takes care of a lot of decision making for you without restricting your flexibility. A key example is how files are named. If you create a model called User, it must be in a file called user.rb. The controller that manages the User resource must then be called UsersController (note how it is preferred to be pluralized), which is contained in a file named users_controller.rb. Rails will automatically choose the correct controller based on the resource name.
Routing
We will take a brief pause from controllers to discuss routing, since this is where it comes in play. The Router in a Rails application controls which HTTP requests (URLs) get processed by which controller actions. For example, this is a route:
get '/patients/:id', to: 'patients#show'
A request sent to your app's /patients/:id endpoint will be processed by the PatientsController's show action.
Note that we've been throwing around the term resource a lot. Rails allows you to define RESTful resources, which come with a prepackaged set of routes. For example, the single line
resources :photos
in your routes.rb will create 7 default routes, shown below:
| HTTP Verb | Path | Controller#Action | Named Helper |
|---|---|---|---|
| GET | /photos | photos#index | images_path |
| GET | /photos/new | photos#new | new_image_path |
| POST | /photos | photos#create | images_path |
| GET | /photos/:id | photos#show | image_path(:id) |
| GET | /photos/:id/edit | photos#edit | edit_image_path(:id) |
| PATCH/PUT | /photos/:id | photos#update | image_path(:id) |
| DELETE | /photos/:id | photos#destroy | image_path(:id) |
This is another example of "Convention over Configuration." These are the standard routes that you should expect for managing a resource.
There is much more to learn about routing, such as nested resources and member/collection routes and shallow nesting. These will come up in your project as you need them, so use this reference to help you out when you find yourself not knowing how to continue!
Strong Parameters
Strong parameters are a security measure enforced by Rails to prevent users from sending malicious data to your application. If you are building an online learning platform, you will not want users to be able to update their progress or grades, as this will conflict with the integrity of your data.
The controllers receive all request parameters in a reserved variable called params. You can access this variable from anywhere in the controller. Consider the following JSON request body for updating a user:
{
"user": {
"name": "Morgana",
"grade": 105.0,
"age": 17
}
}
In your UsersController, params[:user] will contain all of the fields name, grade, and age. However, if you use the following strong parameters:
params.require(:user).permit(:name, :age)
Then, only name and age will be available (grade will be filtered out and thus not modified). Usually, strong parameters are defined in a private method and utilized in the following manner:
class UsersController < ApplicationController
def update
@user = User.find(params[:id])
@user.update(user_params)
end
private
def user_params
params.require(:user).permit(
:name,
:age
)
end
end
Rendering
By default, if you don't return anything in a controller method, Rails will look for and return a view template matching the controller action. For example, consider the following index method:
class UsersController < ApplicationController
def index
@users = User.all
end
end
Without an explicit render statement, Rails will look for a template called index.html.erb in your user views directory and render it to the browser. Note that it is not limited to html (you can return JSON or XML too), and erb is one of many templating engines.
However, if you are using Rails mainly as just an API, then you will likely want data to be returned in JSON format (which your front end can use to render however it wants). You can use explicit renders to achieve this:
class UsersController < ApplicationController
def index
@users = User.all
render json: @users
end
end