Railsでタスク管理ができるWebアプリを作成してみた（Rails入門）

# はじめに

railsを一通り学んだので、自分の課題として簡単なタスク管理ができるWebアプリケーションを作成しましたので、紹介して行きます。

ちなみに、Webアプリケーションとは、HTTPリクエストの中の4つのメソッドを満たす、その名もCRUDメソッド(GET, POST, PUT, DELETE)を使って、Web上のリソースを操作できるアプリケーションのことです。今回作成するWebアプリケーションもその定義通りのものを作成します。

# 環境

- Ruby 2.4.1
- Rails 5.2.0

# プロジェクトの作成

プロジェクト名は**tasklist**とします。

```bash
rails new tasklist --database=mysql --skip-test
```

## コマンドと、コマンドのオプションの説明

- `rails new プロジェクト名`：プロジェクトを作成することができます
- `--database=mysql`：使用するデータベースを`mysql`に指定
- `--skip-test`：自動テスト機能を使用しない

# RailsでWebアプリを作る際の流れ

- 1.モデル（`Model`）の作成
- 2.ルーティングの設定
- 3.ルーティングの設定ごとに`Controller`と`View`の作成

# モデルの作成

RailsとDB（今回は`MySQL`）の接続を行います。

## データベースの作成

Railsが提供しているコマンドでデータベースを作成して行きます。

```bash
$ rails db:create
Created database 'tasklist_development'
Created database 'tasklist_test'
```

```sql
mysql> show databases;
+---------------------------+
| Database                  |
+---------------------------+
| tasklist_development      |
| tasklist_test             |
+---------------------------+
```
（結果を一部省略しています）

`tasklist_test`も作成されますが、こちらは使用しません。

ここで`rails s`でサーバ起動したら立ち上がっていること確認できます。

参考までに、データベースに関する接続設定を管理しているファイルは`config/database.yml`です。
`.yml`の拡張子のファイルは、YAML形式の設定ファイルで、`キー: 値`という形の羅列になっています。
書き方が楽なので、設定ファイルとしてよく使われています。インデントで階層構造を表現するそうです[pug](https://pugjs.org/api/getting-started.html)みたいだね。

## モデルの作成

下記コマンドで、`Task`モデルを作成します。`Task`モデルは`content`というメッセージ内容（文字列）を持つようにします。

```bash
$ rails g model Task content:string
```

モデルを`generate`したらマイグレーションファイルというテーブルを管理するファイルが作成されます。

```ruby:20180606073308_create_tasks.rb
class CreateTasks < ActiveRecord::Migration[5.2]
  def change
    create_table :tasks do |t|
      t.string :content

      t.timestamps
    end
  end
end
```

ファイルの中身ですが、これは`tasks`というテーブルを作成する命令が書かれているマイグレーションファイルです。

このファイルの中身を実行して、テーブルを作成してみましょう。

### マイグレーションの実行

```bash
$ rails db:migrate
== 20180606073308 CreateTasks: migrating ======================================
-- create_table(:tasks)
   -> 0.0052s
== 20180606073308 CreateTasks: migrated (0.0060s) =============================
```

マイグレーションを実行したので、`tasklist_development`データベースに`tasks`テーブルが作成されました。

<img width="511" alt="スクリーンショット 2018-06-06 16.54.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/14191/0a2b0b1a-f4a3-70fe-e39f-daf729a50505.png">

```sql
mysql> describe tasks;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| content    | varchar(255) | YES  |     | NULL    |                |
| created_at | datetime     | NO   |     | NULL    |                |
| updated_at | datetime     | NO   |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
```

指定したのは、`content`カラムだけでした。主キーである`id`、あと、作成時間を記録する`created_at`と、更新時間を記録する`updated_at`は自動で作成されると分かりますね。

# rails consoleを使ってレコードを３件追加する

後々、`view`側で確認するために、`rails console`でレコードを３件追加します。

```bash
$ rails c
```

コンソール内で

- メソッド`new`を使って、モデルのインスタンスを作成
- メソッド`save`を使って、モデルのインスタンスをDBに保存

を、します。

```console
2.4.1 :004 > task = Task.new(content: 'task01')
 => #<Task id: nil, content: "task01", created_at: nil, updated_at: nil> 
2.4.1 :005 > task.save
   (0.3ms)  BEGIN
  Task Create (0.2ms)  INSERT INTO `tasks` (`content`, `created_at`, `updated_at`) VALUES ('task01', '2018-06-06 08:03:49', '2018-06-06 08:03:49')
   (1.8ms)  COMMIT
 => true 
2.4.1 :006 > task = Task.new(content: 'task02')
 => #<Task id: nil, content: "task02", created_at: nil, updated_at: nil> 
2.4.1 :007 > task.save
   (0.1ms)  BEGIN
  Task Create (0.4ms)  INSERT INTO `tasks` (`content`, `created_at`, `updated_at`) VALUES ('task02', '2018-06-06 08:03:56', '2018-06-06 08:03:56')
   (1.9ms)  COMMIT
 => true 
2.4.1 :008 > task = Task.new(content: 'task03')
 => #<Task id: nil, content: "task03", created_at: nil, updated_at: nil> 
2.4.1 :009 > task.save
   (0.1ms)  BEGIN
  Task Create (0.2ms)  INSERT INTO `tasks` (`content`, `created_at`, `updated_at`) VALUES ('task03', '2018-06-06 08:04:01', '2018-06-06 08:04:01')
   (1.7ms)  COMMIT
 => true 
```

SQL内で挿入されたデータを確認しましょう。

```sql
mysql> select * from tasks;
+----+---------+---------------------+---------------------+
| id | content | created_at          | updated_at          |
+----+---------+---------------------+---------------------+
|  1 | task01  | 2018-06-06 08:03:49 | 2018-06-06 08:03:49 |
|  2 | task02  | 2018-06-06 08:03:56 | 2018-06-06 08:03:56 |
|  3 | task03  | 2018-06-06 08:04:01 | 2018-06-06 08:04:01 |
+----+---------+---------------------+---------------------+
```

これでモデルのインスタンス（レコード挿入）の作成を確認できました。タスク管理アプリの作るのに必要なモデルの作成はこれで完了です。

これから、Router と Controller と Viewを一気に作って行きますが、それらの関係を見てみましょう。

# Router と Controller と View の関係を簡単に

- `Router`は、URLのルーティングを一元管理してる
- `Controller`は、HTTPリクエストの処理を担っている
- `View`は、HTTPレスポンスとして返されるWebページ

# ルーティングの設定

CRUDのための基本の7つのルーティングを省略形で書きます。

```ruby:routes.rb
Rails.application.routes.draw do
  root to: 'tasks#index'
  
  resources :tasks
end
```

`root to: 'tasks#index'`は、`/`（TOPページ）と`/tasks`にアクセスしたときのルーティングです。

`resources :tasks`は、CRUDのための基本の7つのルーティングを省略形で書いたやつです。

現状のルーティングを確認して見ましょう。

```bash
$ rails routes
                   Prefix Verb   URI Pattern                                                                              Controller#Action
                     root GET    /                                                                                        tasks#index
                    tasks GET    /tasks(.:format)                                                                         tasks#index
                          POST   /tasks(.:format)                                                                         tasks#create
                 new_task GET    /tasks/new(.:format)                                                                     tasks#new
                edit_task GET    /tasks/:id/edit(.:format)                                                                tasks#edit
                     task GET    /tasks/:id(.:format)                                                                     tasks#show
                          PATCH  /tasks/:id(.:format)                                                                     tasks#update
                          PUT    /tasks/:id(.:format)                                                                     tasks#update
                          DELETE /tasks/:id(.:format)                                                                     tasks#destroy
```
（一部省略）

`root to: 'tasks#index'`と`resources :tasks`が展開されていると確認できます。

この`resources :tasks`で展開された7つのルーティングのことをRESTfulなルーティングと呼びます。RESTfulなルーティングは、リソースのCRUD操作のために必要な7つのアクション(index, show, new, create, edit, update, destroy)です。

# Controller と View を一気に作成

## Controller

以下のコマンドで、`Controller`を生成して行きます。

```bash
$ rails g controller Tasks --no-helper --no-assets
      create  app/controllers/tasks_controller.rb
      invoke  erb
      create    app/views/tasks
```

コントローラ名は**モデルの複数形**で書きます。`Task`モデルに対するコントローラ名は`Tasks`と書きます。

## コマンドと、コマンドのオプションの説明

- `--no-helper`：Helperを自動生成しないオプションです
- `--no-assets`：CSS と JavaScript を自動生成しないオプションです

## Controller を RESTful なルーティングに対応させる

ルーティングに対応したアクションを コントローラーに書いて行きましょう。もう一度、現状のルーティングを確認して見ましょう。

```bash
$ rails routes
                   Prefix Verb   URI Pattern                                                                              Controller#Action
                     root GET    /                                                                                        tasks#index
                    tasks GET    /tasks(.:format)                                                                         tasks#index
                          POST   /tasks(.:format)                                                                         tasks#create
                 new_task GET    /tasks/new(.:format)                                                                     tasks#new
                edit_task GET    /tasks/:id/edit(.:format)                                                                tasks#edit
                     task GET    /tasks/:id(.:format)                                                                     tasks#show
                          PATCH  /tasks/:id(.:format)                                                                     tasks#update
                          PUT    /tasks/:id(.:format)                                                                     tasks#update
                          DELETE /tasks/:id(.:format)                                                                     tasks#destroy
```
（一部省略）

コントローラー内でルーティングと同じ名前のメソッド名として定義すれば対応させられます。

```ruby:app/controllers/tasks_controller.rb
class TasksController < ApplicationController
  def index
  end

  def show
  end

  def new
  end

  def create
  end

  def edit
  end

  def update
  end

  def destroy
  end
end
```

## View

## Viewの構成

`View`ファイルを作成していきます。ルーティングの中で必要な`View`ファイルは`GET`メソッドで指定されたルーティングのみです。（理由：`GET`メソッド以外はページの表示ではなくリソースの操作だから）

そこで、もう一度、現状のルーティングを確認して見ましょう。

```bash
$ rails routes
Prefix Verb   URI Pattern                                                                              Controller#Action
                     root GET    /                                                                                        tasks#index
                    tasks GET    /tasks(.:format)                                                                         tasks#index
                          POST   /tasks(.:format)                                                                         tasks#create
                 new_task GET    /tasks/new(.:format)                                                                     tasks#new
                edit_task GET    /tasks/:id/edit(.:format)                                                                tasks#edit
                     task GET    /tasks/:id(.:format)                                                                     tasks#show
                          PATCH  /tasks/:id(.:format)                                                                     tasks#update
                          PUT    /tasks/:id(.:format)                                                                     tasks#update
                          DELETE /tasks/:id(.:format)                                                                     tasks#destroy
```
（一部省略）

`GET`メソッドのみが`View`ファイル作成の対象なので、 `GET`メソッドのルーティングである`index`,`show`,`new`,`edit`に対応する`View`ファイルをを作成して行きます。具体的なファイルの場所と名前は下記の通りです。

- app/views/tasks/index.html.erb
- app/views/tasks/show.html.erb
- app/views/tasks/new.html.erb
- app/views/tasks/edit.html.erb

`View`ファイルは`rails generate`コマンドは無いので、手作業で作成して行きます。

## 共通部分

`View`ファイルのパスは`app/views/laytous/application.html.erb`です。

この中の、`<%= yield %>`の部分が、コントローラのアクションに関連した`View`ファイル毎に変わります。

## tasks#index

### Controller

インデックスページは、タスクを一覧で全て取得したいからコントローラは下記のようになる

```ruby:tasks_controller.rb
def index
  @tasks = Task.all
end
```

### View

```erb:index.html.erb
<h1>メッセージ一覧</h1>

<ul>
  <% @tasks.each do |task| %>
  <li><%= task.content %></li>
  <%  end %>
</ul>
```

### 確認

現在の`tasks`テーブルの全レコードはこんな感じ

```sql
mysql> select * from tasks;
+----+---------+---------------------+---------------------+
| id | content | created_at          | updated_at          |
+----+---------+---------------------+---------------------+
|  1 | task01  | 2018-06-06 08:03:49 | 2018-06-06 08:03:49 |
|  2 | task02  | 2018-06-06 08:03:56 | 2018-06-06 08:03:56 |
|  3 | task03  | 2018-06-06 08:04:01 | 2018-06-06 08:04:01 |
+----+---------+---------------------+---------------------+
3 rows in set (0.00 sec)
```

こんな感じに出力されていればOK

<img width="745" alt="スクリーンショット 2018-06-06 21.49.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/14191/16aa2a12-990c-c4d6-8871-b2808e2a1bb9.png">

OK ですね。次は、詳細ページ行きましょう。

## tasks#show

こちらは、各タスクの詳細ページです。

### Controller

コントローラは、ここの詳細ページの`id`が取得できればokなので

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

### View

```erb:show.html.erb
<h1>id:<%= @task.id %>のタスク詳細</h1>

<p><%= @task.content %></p>
```

### 確認

今のとこ`~/tasks/1`、`~/tasks/2`、`~/tasks/3`でアクセスしたら詳細ページは見れると思います。

### index から show へのリンクを追加する

`URL`直打ちもあれなので、`index`ページのタスクのidにリンクさせましょう。

```erb:index.html.erb
<h1>メッセージ一覧</h1>

<ul>
  <% @tasks.each do |task| %>
    <li><%= link_to task.id, task %>:<%= task.content %></li>
  <% end %>
</ul>
```

`link_to`はRailsが提供するメソッドです。

`link_to 表示文字列, リンク先` という形式で書きます。

表示文字列はidなので、`task.id`です。

リンク先は、`task`になっています。リンク先として、`task`のようにモデルのインスタンス（レコード）を渡すと、自動的にそのインスタンスの`show`アクションへとリンクされます。

<img width="1128" alt="スクリーンショット 2018-06-06 23.11.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/14191/6ade0675-f353-514c-1ac9-ba162f8408de.png">

#### リンク生成のためのメソッド

もう一度、現状のルーティングを確認して見ましょう。

```bash
$ rails routes
                   Prefix Verb   URI Pattern                                                                              Controller#Action
                     root GET    /                                                                                        tasks#index
                    tasks GET    /tasks(.:format)                                                                         tasks#index
                          POST   /tasks(.:format)                                                                         tasks#create
                 new_task GET    /tasks/new(.:format)                                                                     tasks#new
                edit_task GET    /tasks/:id/edit(.:format)                                                                tasks#edit
                     task GET    /tasks/:id(.:format)                                                                     tasks#show
                          PATCH  /tasks/:id(.:format)                                                                     tasks#update
                          PUT    /tasks/:id(.:format)                                                                     tasks#update
                          DELETE /tasks/:id(.:format)                                                                     tasks#destroy
```
（一部省略）

`Prefix`に`new_task`や`edit_task`があります。`Prefix`があるのは全て`GET`メソッドに対してのみです。ルーティングを設定すると、自動的にリンク生成のためのメソッドも定義されます。上記のようなルーティングが生成された場合には、下記の表のようにメソッドが自動的に生成されます。

| ルーティング | リンク生成のメソッドの例 | 生成されたリンク |
|-----------|------------|------------|
| index       | tasks_path        | /task         |
| show     | tasks_path(@task)      | /task/1 など       |
| new       | new_tasks_path        | /task/new         |
| edit         | edit_tasks_path(@task)          | /tasks/1/edit など           |

リンク生成のメソッドが、「Prefix　& _path」の形式になっています。

次は、タスク作成ページ行きましょう。

## tasks#new

`new`アクションは`POST`メソッドを作成するタスクを入力するフォームのあるページです。

### Controller

インスタンスを作成します。

```ruby:app/controllers/tasks_controller.rb
def new
  @task = Task.new
end
```

### View

フォームは`form_for`を使用して設置します。

```erb:new.html.erb
<h1>タスクの作成</h1>

<%= form_for(@task) do |f| %>
  <%= f.label :content, 'タスク' %>
  <%= f.text_field :content %>

  <%= f.submit '投稿' %>
<% end %>

<%= link_to '一覧に戻る', tasks_path %>
```

### 一覧ページ（index）から新規タスク作成ページ（new）へのリンクを追加する

```erb:index.html.erb
<h1>タスクの作成</h1>

<%= form_for(@task) do |f| %>
  <%= f.label :content, 'タスク' %>
  <%= f.text_field :content %>

  <%= f.submit '投稿' %>
<% end %>

<%= link_to '一覧に戻る', tasks_path %>
```

indexページからのリンクができまして、クリックしたら下のような`View`が出力されると思います。

<img width="281" alt="スクリーンショット 2018-06-07 00.04.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/14191/1697d4ff-87a5-852c-611a-f4dc16bad93d.png">

完成しました。が、投稿ボタンを押しても`create`アクションを実装していないので何もなりません。

次は、それを実装しましょう。

## tasks#create

`create`アクションは、`new`アクションからきた`View`ページから送信されてきたフォームを処理するところです。

### Controller

`new`から`create`へ送られてきたフォームの内容は`params[:task]`に入っていますが、そのまま使用するとセキュリティ上の問題があります。なので、ストロングパラメータというフィルタを使用します。

```ruby
class TasksController < ApplicationController
  #省略

  def create
    @task = Task.new(task_params)
    
    if @task.save
      flash[:success] = 'タスクが投稿されました'
      redirect_to @task
    else
      flash[:danger] = 'タスクが投稿されません'
      render :new
    end
  end

  def edit
  end

  def update
  end

  def destroy
  end
end

private

def task_params
  params.require(:task).permit(:content)
end
```

#### ストロングパラメータに関して

`:content`だけが必要なカラムの場合、このように記述します。

#### privateに関して

`private`は明示するものです。何を明示するかというと、それ以降のメソッドがアクションではなく、そのクラス内だけで使用するメソッドだと明示するものです。

#### 条件分岐に関して

なんの条件分岐かというと、
`@task.save`が成功した場合、つまり、`true`だった場合はif文中のコマンドが実行されます。
`@task.save`が失敗した場合、つまり、`false`だった場合はelse文中のコマンドが実行されます。
`false`になるケースの例でいうと、255文字以上の文字列を入力した場合ですね。`varchar(255)`で入力文字数の限界が255文字なので。

```sql
mysql> describe tasks;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| content    | varchar(255) | YES  |     | NULL    |                |
| created_at | datetime     | NO   |     | NULL    |                |
| updated_at | datetime     | NO   |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
```

#### flashに関して

`flash`は投稿が正常に行われたことを知らせる機能です。後ほど`view`を実装して行きます。

#### redirect_to と render の違い

一番の違いは、`redirect_to`はHTTPリクエスト（`GET`メソッド）を発生させ、renderは発生させないところです。

「GET」「/tasks/:id」というHTTPリクエストが送られるので、ルーティングに従って、Tasksコントローラーの`show`アクションの処理に移り、その結果として、詳細ページが表示される、ということですね。

参考
https://qiita.com/january108/items/54143581ab1f03deefa1

`@task.save`が成功した場合、`redirect_to リンク先`は、リンク先（`@task`のshowルーティング）に強制的に飛ばすメソッドです。
そして、`show/id`を出力して、`flash`が出て保存されたことがわかります。

`@task.save`が失敗した場合、`render :new`なので、`new.html.erb`に直接飛びます。

### View

保存に成功した場合、`/tasks/:id`へリダイレクトします。

```erb:show.html.erb
<h1>id:<%= @task.id %>のタスク詳細</h1>

<p><%= @task.content %></p>

<%= link_to 一覧へ戻る,tasks_path %>
```

ここで、フラッシュメッセージ(`flash`)を表示させるための、設定をして行きます。

```erb:/views/layouts/_flash_tasks.html.erb
<% flash.each do |task_type, task| %>
  <div><%= task %></div>
<% end %>
```

全ての`View`で表示させたいので、`/views/layouts/application.html.erb`に`render`させます。

```erb:/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>Tasklist</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= render 'layouts/_flash_tasks' %>
    
    <%= yield %>
  </body>
</html>
```

これで、`flash`に代入されるとメッセージが表示されるようになります。`flash`は、`Controller`から`View`へ、ハッシュの形式でメッセージを渡します（`{ success: 'タスクが投稿されました' }`）←こんな感じ。`success`とか`danger`にしているのは、bootstrap都合です。

参考
https://qiita.com/youcune/items/12b153c08db695952e47

次は、タスク編集機能へ行きましょう。

## tasks#edit

### Controller

編集するページのidが知りたいので

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

### View

`new`の`view`ファイルとほぼ同じです。

```erb:edit.html.erb
<h1>タスクの編集</h1>

<%= form_for(@task) do |f| %>
  <%= f.label :content, 'タスク' %>
  <%= f.text_field :content %>

  <%= f.submit '投稿' %>
<% end %>

<%= link_to '一覧に戻る', tasks_path %>
```

では`show`の`view`ページから、`edit`の`view`ページにリンクさせましょう。

```erb:show.html.erb
<h1>id:<%= @task.id %>のタスク詳細</h1>

<p><%= @task.content %></p>

<%= link_to '一覧へ戻る', tasks_path %>

<%= link_to '編集ページへ', edit_task_path(@task) %>
```

次は、タスク更新の機能作成を実装しに行きましょう。

## tasks#update

コントローラ部分は、`create`アクションに似ています。

### Controller

```ruby:tasks_controller.rb
def update
  @task = Task.find(params[:id])
    
  if @task.update(task_params)
    flash[:success] = 'タスクが編集されました'
    redirect_to @task
  else
    flash.now[:danger] = 'タスクが編集されませんでした'
    render :new
  end
end
```

![スクリーンショット 2018-06-07 21.37.36.png](https://qiita-image-store.s3.amazonaws.com/0/14191/adb72738-a9aa-aa6a-9ced-90af12584d53.png)

`create`アクションと異なるところは、①と②の部分です。なぜ違うかというのは、手順を説明すればわかるかと思います。

- `tasks/id`（タスク詳細ページ）にある「編集ページへ」リンクをクリック
- `edit`アクションが呼ばれる
- 編集して、投稿ボタンを押すとおそらく`update`アクションに行く
- `update`アクションとしては、どの`id`を編集・更新すべきかわからないのでそれを取得しようとしてる（それが①）
- 取得した`id`がストロングパラメータ（`task_params`）を通過した後、`:content`があればif文中が実行。なければelse（それが②）

### View

不要です。

次は、タスク削除に行きましょう。

## tasks#destroy

### Controller

```ruby:tasks_controller.rb
def destroy
  @task = Task.find(params[:id])
  @task.destroy
    
  flash[:success] = 'タスクが削除されました'
  redirect_to tasks_path
end
```

　リダイレクトする際、今までは`prefix_path`を利用してきましたが、リダイレクトの場合だけは`~_url`を使用しましょう。

### View

削除用の`View`は不要です。

ただ、削除用のリンクは必要なので、`show`ページに書きましょう。

```erb:show.html.erb
<h1>id:<%= @task.id %>のタスク詳細</h1>

<p><%= @task.content %></p>

<%= link_to '一覧へ戻る', tasks_path %>

<%= link_to '編集ページへ', edit_task_path(@task) %>

<%= link_to '削除する', @task, method: :delete, data:{ confirm: '本当によろしいですか？'} %>
```

method: :delete は`DELETE`メソッドを送信することを明示しています。`data: { confirm: ... }`はJava Scriptの記述です。

---

これで、自分のRails学習用課題である、全てのCRUDメソッド(GET, POST, PUT, DELETE)を使って、Web上のリソースを操作できるアプリケーション作成が完了です。

# レポジトリ

https://github.com/ryosuketter/kadai-tasklist

# 参考

- https://railsguides.jp/
- https://qiita.com/january108/items/54143581ab1f03deefa1
- https://qiita.com/youcune/items/12b153c08db695952e47