We've successfully created routes for our record store application. Each route has a corresponding controller action. Now it's time to create our controllers and the necessary CRUD actions that go with this.
Navigate to app/controllers and add the following files:
songs_controller.rb. Note that these files must follow a specific naming convention in order to work:
Let's start with our
albums_controller.rb. We'll create a basic controller that has all seven actions listed. None of the actions will do anything yet, but each has a comment specifying what it will do.
class AlbumsController < ApplicationController def index # Code for listing all albums goes here. end def new # Code for new album form goes here. end def create # Code for creating a new album goes here. end def edit # Code for edit album form goes here. end def show # Code for showing a single album goes here. end def update # Code for updating an album goes here. end def destroy # Code for deleting an album goes here. end end
Once again, note the naming convention of
AlbumsController. This needs to be pluralized and upper camelcase.
AlbumsController inherits from
ApplicationController which in turn inherits from
ActionController::Base. Just as our models folder has an
application_record.rb file, our controllers folder has an
application_controller.rb file. This file will contain any code that belongs in all controllers.
Next, we have our seven actions in the form of Ruby methods. These methods will always have the same names:
destroy. If we have custom routes in our application, we'd also have custom methods for those routes. And if we were to use either
:except to specify that a group of resources should have fewer than seven routes, that would be reflected in our controller as well.
Much of the code in our controller will look very similar to the code we added to
app.rb in the last section. Let's take a look one route at a time.
... def index @albums = Album.all render :index end ...
index action will use
Album.all and store the list of albums in
@albums so it will be available in the view. This is exactly the same as our code from the last section.
Then we use the
render method to return the corresponding view. We could use a custom name but that's not the Rails convention. Our application will automatically look for a view corresponding to
albums#index. We'll cover that in the next lesson when we explore views further.
One other thing to note: Rails is so helpful that we can omit the
render method altogether if the view is the same name as the controller action and the view is stored in a folder with the same prefix as the controller. This means that if we name our view
index.html.erb and store it in the subdirectory views/albums (which we should do), Rails will automatically know that is the correct view for this action. We will continue to add the
render method to make our code explicit but this is one more thing that Rails can take care of for us.
... def new @album = Album.new render :new end ...
new route first instantiates a new
Album and stores it in an instance variable called
@album. This is because the form in our view will need access to an instance of
Album. This will be clear when we create the view for the form in the next lesson.
Here's our new
... def create @album = Album.new(album_params) if @album.save redirect_to albums_path else render :new end end # Other controller methods go here. private def album_params params.require(:album).permit(:name, :genre) end end
The code we need for our
create method includes two parts. We'll start by looking at the
create method itself.
* First, we instantiate a new
Album with the
album_params from the form. We save this value in the instance variable
* Next, we have a conditional
if @album.save. Remember that
#save returns a boolean while
#create returns the created record.
* If the album is saved (and the boolean returns true), we'll
albums_path. Remember the prefixes from
rake routes? We combine the prefix
albums corresponds to the
index route of our
AlbumsController so the code inside
def index will run.
redirect_to is self-explanatory: it redirects to the path given as an argument.
* If the album isn't saved and the boolean returns false, we'll just
render :new again.
Now let's take a look at the code under
private. Private methods are available only inside the class. That means any methods included under
private will only be available inside the
AlbumsController class. It's important that we include this code at the end of the class (just above the final
end); we wouldn't want to accidentally make any of our controller actions private.
We define a new method called
album_params. This is the same
album_params we've passed into our
create action. This method lets our application know which parameters can be passed into our methods. These are called strong parameters. This is a security feature to protect our database from being attacked. Currently, we only allow two parameters to be passed into an
genre. If someone were to try to pass another parameter in, it would be rejected.
The format of the code in this method will always look like this:
Make sure that you always add all the properties you want a user to be able to modify to this method. If you are having problems passing parameters into an object, verify that you've added this method along with any necessary parameters. This is a common error for beginners because our application will not throw an exception for missing parameters.
edit action will look familiar from the last section:
def edit @album = Album.find(params[:id]) render :edit end
Rails has a
params hash just like Sinatra. We use the
Album#find method to find an
Album instance by the
id passed in via
params. Then we will
render the corresponding
edit form for this controller.
show action looks almost exactly the same as our
edit action. The only difference is that we'll render the
show view instead.
def show @album = Album.find(params[:id]) render :show end
update action looks very similar to our
def update @album= Album.find(params[:id]) if @album.update(album_params) redirect_to albums_path else render :edit end end
First, we find the instance of
Album based on the
:id parameter and save it as
@album is successfully updated, our application will
index route). Otherwise, it will
render the edit form again. Note that the
update method relies on
album_params just like the
save method in the
create action does.
The code for destroying an
Album instance is straightforward:
def destroy @album = Album.find(params[:id]) @album.destroy redirect_to albums_path end
We find the correct
Album instance, use ActiveRecord's built-in
destroy method to delete it, and then
Each of these actions has functionality that's very similar to what we did in the last section with Sinatra. Either one or all albums are stored in an instance variable so that they can be used in the view. Sometimes these albums are saved or modified. Once the code is finished running, a view is rendered or there is a redirect to another route.
In the next lesson, we'll create the corresponding views for our
AlbumsController. We'll build out the
SongsController and its corresponding views in a future lesson.
Lesson 10 of 34
Last updated July 14, 2022