Exploring how a new model and UI is created in Rails using `rails generate scaffold`
Tags: rails
Published: 2020-05-16 05:37:27

---
title: Exploring how a new model and UI is created in Rails using `rails generate scaffold`
published: true
date: 2020-05-16 05:37:00 UTC
tags: rails
canonical_url: https://www.emgoto.com/rails-model-scaffold/
cover_image: https://www.emgoto.com/rails-model-scaffold-dev.png
series: [Getting started with Rails and Preact]
---

As a newbie to Rails and Ruby, I found the code generated by the `rails generate scaffold` command initially very hard to understand. A lot of Googling later, I think I have a better understanding of what things are doing, and so I decided to write a post about it!

## Running the generate scaffold command

If we were to create a to-do list app, we would need a way of storing our tasks in a database. With Rails, we can do this using something called a **model** - which acts like a wrapper aorund a database table. 

In our case, we are going to need a table that stores tasks, and so we need to create a `Task` model that stores the task's name, due date, and whether it has been completed or not.

We can call `rails generate scaffold` with the name of our model, and any number of arguments in the shape `fieldName:dataType`:

```ruby
rails generate scaffold Task name:string done:boolean due:datetime
```

Note that you don't need to specify an ID - Rails will handle this one for you.

> If you're not sure what data types to use for your fields, I found [this StackOverflow answer on data types]([https://stackoverflow.com/a/22725797/5452368](https://stackoverflow.com/a/22725797/5452368)) really useful.

One of the new files created by this command will be a new file in `db/migrate` that will look something like this:

```ruby
class CreateTasks < ActiveRecord::Migration[6.0]
  def change
    create_table :tasks do |t|
      t.string :name
      t.boolean :done
      t.datetime :due

      t.timestamps
    end
  end
end
```

To create a table of tasks in our database, we will need to run that file. We can do that with the following:

```ruby
rails db:migrate
```

Now that your database can handle storing tasks you can start up your app:

```ruby
rails s --binding=127.0.0.1
```

You will see that at `http://localhost:3000/tasks`, Rails has generated a basic UI for you that lets you create, delete and edit tasks - all for free! (I was actually pretty amazed by this). I recommend having a little play around with it and creating a few tasks.

In the next section, we'll be exploring how all this UI has been generated for us.

## How tasks routing works

If we take a look at `config/routes.rb` we will see a new line has been added:

```ruby
resources :tasks
```

This is a shorthand for [7 separate routes]([https://guides.rubyonrails.org/routing.html#crud-verbs-and-actions](https://guides.rubyonrails.org/routing.html#crud-verbs-and-actions)) that allow you to view, modify and create tasks. 

e.g. two of them would be: 

```ruby
get '/tasks' 'tasks#index'
post '/tasks' 'tasks#create'
```

Each line maps a URL to a controller and action, so if we make a GET call to `/tasks`, we will execute the code inside of the `index` action in the `tasks` controller.

## What's happening in the tasks controller?

The `tasks` controller is another file that has been generated for us at `app/controllers/tasks_controller.rb`. I'm going to break down some of what is happening.

### before_action

Right up the top of the file, you'll see this:

```ruby
before_action :set_task, only: [:show, :edit, :update, :destroy]
```

Here we're saying that the `set_task` method (which is defined near the bottom of the file) should be called before the given list of actions (show, edit, update and destroy).

> The colon (`:`) before `set_task` indicates that it is a [Symbol](http://rubylearning.com/satishtalim/ruby_symbols.html]), which is like a reference to the method. If we didn't use the colon, `before_action` would use the results of calling the `set_task` method.

### set_task

That `set_task` method does the following:

```ruby
def set_task
    @task = Task.find(params[:id])
end
```

- `@task` - In Ruby, the `@` defines a variable as an instance variable, which means it can be accessed outside of where it has been defined (even in the view file!)
- `Task` - Refers to the Task class that lives in `models/task.rb`.
- `Task.find()` - we can call `find(id)` on the model, which will find the task that matches the ID we passed in
- `params` - this object contains any parameters defined in the routes file. In our case one of our routes is `get '/tasks/:id'` so if a user lands on `localhost:3000/tasks/2`, then in our params object there will be an `:id` with a value of `2`.

In short, before we do certain things like viewing a specific task or deleting one, we will store in `@task` the relevant task that we are looking for. This means each action that access it immediately without having to add in that extra line of code themselves.

### Getting all tasks using the index action

Now the first action is our index action. This maps to the following route:
```ruby
get '/tasks' 'tasks#index'
```
The action itself is very short:

```ruby
def index
  @tasks = Task.all
end
```

What we're doing here is storing a list of all the tasks in `@tasks`.

And then with Rails magic, this action will map to the view file defined at `tasks/index.html.erb`. This view file will have access to all the tasks, and can loop through them and render them all on the page: 

```ruby
<% @tasks.each do |task| %>
    <tr>
        <td><%= task.name %></td>
    </tr>
<% end %>
```

### Updating a task using the update action

The update action maps to the following route:

```ruby
put '/tasks/:id' 'tasks#update'
```

```ruby
def update
    respond_to do |format|
      if @task.update(task_params)
        format.html { redirect_to @task, notice: 'Task was successfully updated.' }
        format.json { render :show, status: :ok, location: @task }
      else
        format.html { render :edit }
        format.json { render json: @task.errors, status: :unprocessable_entity }
      end
    end
end
```

Let's break this down!

- `respond_to` - a method available to us in controller classes, which will give access to a `format` method
- `@task` - we got this from the `set_task` method (described above)
- `@task.update()` - we can call `update()` on the specific task, and pass in new values
- `task_params` - gives us the values in the body of the call that was made (described in more detail below)
- `format.html` and `format.json` - we're defining what is returned, depending on if the request was an HTML or JSON request.
- `if` and `else` - if `@task.update` fails, we will enter the `else` block.

### task_params

The other method defined at the bottom of the file is `task_params`:

```ruby
def task_params
    params.require(:task).permit(:name, :done, :due)
end
```

When this method is called, we will require that a `:task` symbol exists inside of the params object, and filter out any values from task that aren't the values for name, done and due.

What this means in practice is that if you called the endpoint with the data to create a new task, this would be accessible inside of `params[:task]`. And if you passed in an extra field like "description", this would get filtered out by this method.

---

And that's it for this post! The other actions are fairly similar to the code I've gone through above, so hopefully shouldn't be too hard to understand. 

Thanks for reading!