とりあえずこれだけ。Rails ToDoアプリ作成【CRUD】勉強会 #1

# 初心者用Railsアプリ練習帳

勉強会を開き、Rails初学者に日頃教えています。初心者向け勉強回資料用もかねて作成。
ある程度基礎を学習していると、読みながら真似はできるけど、いまいち全体の知識がつながっていないので自分で作ることができない…

そんな状態になりがちでした。

## 対象者
- Railsでなんでもいいからの教材をやった人
- Rails基礎はなんとなくわかってきた人
- Railsで自分でアプリ作るのはまだ無理そうという人
- Rails以外のフレームワークならわかる人

**※ 正確さより概念とアプリ作成の流れを重視します。**

## コンセプト
他にも言っている方がいますが、勉強会で教えている経験から初学者が同じ教材を何周もするのは上達が遅いように感じています。

知識はあるけど自分で一から作るのは無理そう。
エラーが出て対処出来ない

ということになりがちでした。


こういう場合、実際に手を動かし、自分の頭で考えて簡単なアプリを作る必要があるけど、

- いきなりだと何を作ればいいのかわからない…
- 一連のアプリを作っていく順番がわからない…
- エラーでても対処できない…
- 簡単なのから作ってみればいいと言うが何が簡単なものなのか分からない…
- 何個もアプリ自分で作るといいらしいが何を作れば練習やスキル向上なるか分からない…


そんな人が未経験からプログラミングをやる人には何人もいました。
現状の私の考えですが、世の中にある教材は見た目とか完成度ないと売れないし、強い人達からツッコまれるので分かりやすさより精確さが必要とされる教材になってしまうようにおもいます。

なので、後で身につければ良いこともあれもこれも付け足しており、本当にコレだけ！
という事項が初心者には見えにくくなっている気がします。


それをうけて今回、ムダなものとにかく剥ぎまくって、コアな部分だけを数多く練習すればみんな出来るようになるのではないかと考え、練習問題を作りました。
今後も感想とかもらって継続的にブラッシュアップしていければと思っています。

# 手順

1. とりあえずToDoアプリをなぞって作ってみる(少しだけでも勉強した人が前提)　←今回はココ
2. 超シンプルアプリを量産。手を動かして覚える！概念つかむ！
3. データベースから欲しいデータを取得する！千本ノックのようにやりまくります！


2,3は個人的に開く勉強会で解説します。


# とりあえずToDoアプリをなぞって作ってみる

環境構築はローカルでもいいですけど、WindowsやMacで違うので初心者はcloud9で作っていいと思います。
構築方法は今回省略

以下のコマンドでアプリを作成。プロジェクト名になります。なんでもいいです。
今回、私は`rails-todo1`にしました

```
$ rails new rails-todo1
```

沢山のファイルが作られる。終わったらプロジェクトのディレクトリに移動

```
$ cd rails-todo1
```

サーバーを起動させて表示させてみる

```
$ rails s
```

<img width="661" alt="welcome_rails.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/d64dfe93-98d5-6c3d-fec4-ec5b7ac579f5.png">

こんな画面が出たらOK

# これから中身を作っていくので一応流れを確認
今回新規作成で一から作っていきますが、だいたいこんな感じで作ると考えていただければよいかと思います。


# 新しいアプリ（ページ）を作る手順

全体の流れで考えること

1. 作るページはどんなページで作る？
2. データベースに保存するデータは何か？
3. モデルは作ったか？
4. マイグレーションファイルを生成＆データベースに反映
  - `generate modelコマンドするとmigrationファイルも作られる。`
  - `カラム（データベースの列）を追加したり、データベースの中身を変えたいときにもマイグレーションファイル使う`
  - `rails db:migrate`でマイグレーションファイルの内容をデータベースに反映
5. ページを表示するのか？データを登録・更新をするのか？
  - `表示するならGET`
  - `データの登録ならPOST`
  - `データの更新ならPATCH (PUT)`
  - `データの削除ならDELETE`

6. ルーティングを決める
 - `URLにパラメータをいれる必要があるのか？（例えば各ユーザーの情報ページを表示するならparams[:id]のように書く。ならばURLに〇〇〇/:idのようにidを含める必要がある）`
 - `URLにパラメータいらない（新規登録や全データ表示など）`

7. 処理を行うコントローラーは作ったか
8. コントローラーのアクションは作ったか
  - `GET？POST？PATCH？DELETE？`かを確認してつくる
9. ビューファイルはいるか？

# さっそく簡単なアプリ作成していく

## 1.どんなもの作るか

↓　なんの飾りもない超シンプルアプリ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/0f21535b-cd19-75b6-79fc-88740427571c.png)


テキストを入力して登録する
![todo2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/f86e1613-e378-88c4-421c-86f80497e919.gif)


## 2.データベースに保存するデータは何か
- テーブル名：Todo
- カラム名：title
- デフォルトで作られるカラム(ID, 作成日, 更新日)

## 3. モデルは作ったか
今回は、まだ何もつくってないので当然必要。
今回作るToDoアプリでは、Todoテーブルの`データ取得・新規登録・データ更新・データ削除`を行うのでModelを1つ作成します

というわけで、モデル作成。

```
$ rails generate model Todo title:string
```

2.で書いたように必要なテーブルが`Todo`
必要なカラムが`title`なので、このように書いています。

① `rails generate model Todo`でモデルファイルが作られる
② ` title:string`部分は追加したいカラム名と型。
この部分は書かなくても手動で記述すれば作れるのですが、コマンドでこのように打ったほうが楽です

```.rb:db/migrate/~~~~~~~~~_create_todos.rb
class CreateTodos < ActiveRecord::Migration[5.2]
  def change
    create_table :todos do |t|
      t.string :title

      t.timestamps
    end
  end
end
```

### 補足：モデルとは
普通はデータベースからデータを取得するときには`SQL`というものを書かないといけなくて初心者にはそれなりに複雑。
Railsではmodelというものを使うとSQL書かなくてもデータ取得できて便利。


## 4. マイグレーションファイルを生成＆データベースに反映
今回新規作成なのでモデルをつくるとmigrationファイルも作られるのでコマンドでmigrationファイルを作る必要ありません。

マイグレーションファイルの内容をデータベースに反映させるコマンド打つ

```
$ rails db:migrate
```

### 補足：migrationファイル作る必要あるときは

migrationファイルとは：
データベースのテーブルの作成、変更を記述するためのファイルで、`rails db:migrate`を実行することでデータベースに反映させる。

<details><summary>【コマンド詳細】カラムの追加。今回は実行必要しないでください</summary><div>

```
$ rails generate migration add_password_digest_to_users password_digest:string
```
こんな感じのコマンド入れてカラムの追加とかやります。
今回は当然新規必要なし。
実行すると`migrate`でエラーになります。
</div>



## 5. ページを表示するのか？データを登録・更新をするのか？
`→ 表示するならGET`
`→ データの登録ならPOST`
`→ データの更新ならPATCH (PUT)`
`→ データの削除ならDELETE`

今回は最初のページが
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/b4ca2674-2687-be68-e1a7-977e214bdc9c.png)

Todoを追加するための機能を持つページを「表示」します。
ということで`GET`メソッドです

## 6. ルーティングを決める
ルーティングは
**どのURLにアクセスすると、どのコントローラーとアクションを使うのか**定義するものです。

Railsには`resources`という便利機能があってルーティング書くのを便利にできる機能があるんですが、今回は原理を理解するために今回は一つ一つルーティングを記述していきましょう。

```config/routes.rb
get '/todos', to: 'todos#index', as: 'todos'
post '/todos', to: 'todos#create'
```

### ルーティングを確認する

コンソールに↓を入力するとルーティングを確認できる。

```
$ rails routes
```

```
Prefix  Verb  URI Pattern     Controller#Action
todos   GET  /todos(.:format) todos#index
        POST /todos(.:format) todos#create
```


もしくは
`/rails/info/routes`をアドレスバーにつけると少し見やすい画面になる
`http://sample.com/rails/info/routes`みたいな感じ
他タブで開いておくといちいちコマンド入れなくても確認できるので便利！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/5d076b31-b985-528e-d537-5b5318f76749.png)



現状では`/todos`にGETを設定して`todoコントローラー`の`indexアクション`の処理を使えと指定している

### 補足：_pathについて
`$ rails routes`だと`Prefix`が`todos`という名前になっていてURLに名前を付けて便利に使えるようになっている。これに`_path`を追加すると使えます。
`todos` + `_path`で`todos_path`です。

`todos_path`と書くと`/todos`と書いたのと同じことになります。
結構使いますので覚えておくといいです。

## 7. 処理を行うコントローラーは作ったか

コントローラーは大雑把に`ルーティング`と`モデル`と`ビュー`をつなぐ役割、データ返す役割をしているものです。

![mvc_pattern.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/c102a488-6a72-af29-4ad7-b482429152a5.png)

### コントローラーは何をするか雑に説明

細かく言うとわかりにくくなるので大雑把に。

- ルーティングで該当のURLにマッチしたら、コントローラーのアクションに処理が飛んでくる。そして処理を行う。
    - その際に`params`のデータもらうこともあり
- `Todo.new`使ってビューファイルで記述する`form_with`(form_forも含む)で使うフォームでデータを送信するために必要なモデルの部品みたいなものが入った箱作ったりする。
    - ビューで使うならインスタンス変数に格納する
- `Todo.find(params[:id])`みたいに自分で作った`Model`使ってデータベースの値を取得する。
    - `Todo.find(params[:id])`は`Todo.new`で作った部品に、取得したデータも含んだものだと思っておけばいいです。※下図参照
    - ビューで使うならインスタンス変数に格納する
- インスタンス変数はビューで使用可能なのでページを操作によってデータ表示やフォームの送り先を変えられる動的なページを作れる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/9c7d6179-a1d8-948c-c068-e17c8a343900.png)

初心者のうちはデータ取得したり、データを加工する、ビューで表示するためのデータを`@todo`みたいなインスタンス変数を作る！
みたいな感じでいいと思います。

### コントローラー作成コマンド
以下コマンドで、Controllerを作成します。

とりあえずコントローラーを生成する

```
$ rails g controller Todos
```

このコマンドならtodosというコントローラー作成されるので、`todos_controller.rb`というファイルができます。

## 8. コントローラーのアクションは作ったか

```app/controllers/todos_controller.rb
class TodosController < ApplicationController
  def index
    @todos = Todo.all
  end
end
```

コントローラーの処理を書いてみました。
Todoテーブルに入っているデータを全件取得(allメソッドを使う)してインスタンス変数の`@todos`に入れています。



## 9. ビューファイルはいるか？
ビューファイルは表示部分です。
htmlっぽい書き方だけどコントローラーなどで処理したインスタンス変数などを使って静的なページでなく動的なページを作ることができます。

さきほど、`@todos`というインスタンス変数をコントローラーのindexアクションに書いたので、これを作って全データを表示してみましょう。

index.html.erbが存在しない場合は`app/views/todos/index.html.erb`に作成しましょう。


```.erb:app/views/todos/index.html.erb
<h1>ToDo一覧</h1>
<table>
  <thead>
    <tr>
      <th>タスク</th>
    </tr>
  </thead>
  <tbody>
    <% @todos.each do |todo| %>
      <tr>
        <td><%= todo.title %></td>
      </tr>
    <% end %>
  </tbody>
</table>
```

### 作成した画面

まだデータの登録がないので全件取得しても表示するものがないので、このような表示になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/b4ca2674-2687-be68-e1a7-977e214bdc9c.png)

こんな1～9までのような順序でアプリの作成（もしくは追加）をしていくことになります。

では、次にTodoの全件表示しかできない状態なので
次は新規ToDo追加できる機能を追加します



## 新規追加機能の作り方
次に新規登録できる機能を作ります。
今度は1～9まの順序で機能を追加していきましょう。

## 1.どんなもの作るか
ToDoテーブルにデータを新規追加する機能
テキストフィールドに入力した文字をボタン押すとデータベースに登録

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/c431e13f-f987-4ad4-1e76-b8c26f46be37.png)


## 2.データベースに保存するデータは何か

テーブル名：Todo
カラム名：title
デフォルトで作られるカラム(ID, 作成日, 更新日)

`title`だけデータベースに保存すればいいことになります。


## 3. モデルは作ったか

モデルはTodoつかうので新しく作成の必要なし

## 4. マイグレーションファイルを生成＆データベースに反映

モデルはTodo使う。カラムの追加も必要ないのでマイグレーションファイル作る必要も、データベースに反映する必要もない。

## 5. ページを表示するのか？データを登録・更新をするのか？
カラム名で`title`をデータベースに登録する処理を追加することになります。

ページの表示をしているわけでも、情報の更新をしているわけでもなく、情報の削除でもありません。

こういうデータの登録処理は`POST`で行いましょう。

## 6. ルーティングを決める

- メソッド：`POST`
- ルーティング：`/tasks`
- コントローラー＆アクション`tasks#create`

### ルーティングを確認
実はすでに追加してしまっていたのですが、今回使うルーティングは↓の二つ目です。

```routes.rb
Rails.application.routes.draw do
  get '/todos', to: 'todos#index', as: 'todos'
  post '/todos', to: 'todos#create'
end
```
ページを表示しないで新規登録を行うのでPOSTですね。

## 7. 処理を行うコントローラーは作ったか

新しいモデルを作ったわけでも、わざわざ新しいコントローラーをつくる必要もありません。
`todo`テーブルのToDoのデータ追加処理を追加するのでコントローラーは`todos_controller.rb`に追記すればOKです。

## 8. コントローラーのアクションは作ったか

データ追加処理を記述したアクションを`todos_controller.rb`に追記していきましょう。

### コントローラーにアクションを追加

`create`を追加しました。新規登録を行うためのアクションになります。

```app/controllers/todos_controller.rb
class TodosController < ApplicationController
  def index
    @todos = Todo.all
    @todo = Todo.new # フォーム作るために必要
  end
  
  def create
    @todo = Todo.create(todo_params)
    redirect_to todos_path
  end
end
```

`redirect_to todos_path`
としているのは、ページを表示しているわけでないのでリダイレクトしないと処理が終わっても処理が固まった感じになってしまうからです。

処理としては正常に終了してるけど、↓のように何も起こってない…みたいな感じになる。
正常に登録はできているのでリロードするとちゃんと表示されることになる。

![todo1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/ef322122-4e04-4f33-4245-ea40b407a94b.gif)


`get '/todos', to: 'todos#index', as: 'todos'`
の`as: 'todos'`と書くと`/todos`というURLに`todos`という名前を付けて使えるようにしています。

この名前に、`ルーティングの名前（todosなど）` + `_path` で `todos_path`
のようにするといちいちURLを書く必要がなくなります。


注意点として、Formで入力した情報を新規登録や更新する際はセキュリティ対策として`Strong Parameters`を使わないとエラーでますので追加します。

### Strong Parameters
セキュリティ対策で、入れないとエラーになります。
難しいこと省いて、フォームから受け取ったデータを渡すと、許可したデータだけ返却されるくらい覚えておけばとりあえずは良いと思います。


そして追加したのが`todo_params`メソッド。また、`private`を使うと、todo_paramsメソッドが外部から使えないようにできるのでセキュリティを高まります。
難しいことはいいので、privateの下に`Strong Parameters`いれるんだなくらいで今はいいです。

```app/controllers/todos_controller.rb
class TodosController < ApplicationController
  def index
    @todos = Todo.all
    @todo = Todo.new # フォーム作るために必要
  end
  
  def create
    @todo = Todo.create(todo_params)
    redirect_to todos_path
  end
  
  private
    def todo_params
      params.require(:todo).permit(:title)
    end
end
```

## 9. ビューファイルはいるか？

データベースでのデータの追加処理では使いません。
ただし、送信するための`テキスト入力フォーム`と`送信ボタン`を`index.html.erb`に登録したいと思います。

### テキスト入力フォームと送信ボタン

```.erb:index.html.erb
<h1>ToDo一覧</h1>
<table>
  <thead>
    <tr>
      <th>タスク</th>
    </tr>
  </thead>
  <tbody>
    <% @todos.each do |todo| %>
      <tr>
        <td><%= todo.title %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<h2>ToDo追加</h2>
<%= form_with model: @todo do |f| %>
  <div><%= f.label :title %></div>
  <div><%= f.text_field :title %></div>
  <div><%= f.submit %></div>
<% end %>
```

フォームを作るために`form_with`を使っています。
また、使うmodelを指定する必要があるので`@todo`を指定してます。
コントローラーのindexアクションで追加します。

`f.label`のようにすると「Title」というラベル（文字表示）され、
`f.text_field`は文字を入力するフォームを作ることができる。
`f.submit`は送信ボタン。


`todos_controller`の`index`にフォームを作るための部品を用意するため`@todo = Todo.new`を追加

```app/controllers/todos_controller.rb
class TodosController < ApplicationController
  def index
    @todos = Todo.all
    @todo = Todo.new # フォーム作るために必要
  end
end
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/8902a14e-41d4-414c-18c0-c811bfa1bca0.png)


## 登録機能完成
データベースに登録する機能が完成しました！

![todo2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/f86e1613-e378-88c4-421c-86f80497e919.gif)


# 今度は更新と削除

次は更新機能を実装します。

## 必要機能
- 情報更新ページ（今回はeditアクションとedit.html.erbにて）
    - ルーティングを追加する
    - editアクションで編集する情報を表示する　todos_controller.rb
    - ビューで見た目を作る　edit.html.erb
- 情報更新処理
    - updateアクションで情報の更新処理　todos_controller.rb

### 更新情報編集ページ用ルーティング追加

```routes.rb
Rails.application.routes.draw do
  get '/todos', to: 'todos#index', as: 'todos'
  post '/todos', to: 'todos#create'
  
  get '/todos/:id/edit', to: 'todos#edit', as: 'edit_todo'
end
```

`get '/todos/:id/edit', to: 'todos#edit', as: 'edit_todo'`を追加しました。

`todos_controller.rb`の`edit`アクションを使用します。ルーティングの名前は`edit_todo`とでもしておきます。

### 更新情報編集ページ用コントローラー

editアクションは、情報編集画面（/todos/:id/edit）にアクセスすると処理されるアクションで、ビューで見た目を作るときに必要なデータの取得します。


editアクションを情報を追加します。

```todos_controller.rb
  def edit
    @todo = Todo.find(params[:id])
  end
```

- `@todo`はインスタンス変数。`@`とつけることでビューでもデータを使えるようになります。
- `find`はデータベースの`id`カラムからデータを探し出すときに使います。
    - idはtodoを追加したときに自動的に採番されていきます。データベースの中身は下の表みたいになる。
- 編集画面は（/todos/:id/edit）のようにルーティングで設定した。
    - 例えばURLが`http://sample.com/todos/1/edit`だとすると`params[:id]`は`1`
    - `http://sample.com/todos/3/edit`だとすると`params[:id]`は`3`
    - `http://sample.com/todos/1/edit`だとすると`@todo = Todo.find(1)`と書いているのと同じになる

試しに登録したデータベースの内容が↓になります。


| id | title  | created_at                 | updated_at                 |
|----|--------|----------------------------|----------------------------|
| 1  | テスト | 2019-10-18 04:05:36.776003 | 2019-10-18 04:05:36.776003 |
| 2  | 買い物 | 2019-10-18 04:05:43.090180 | 2019-10-18 04:05:43.090180 |
| 3  | 勉強   | 2019-10-18 04:05:51.098753 | 2019-10-18 04:05:51.098753 |

`@todo = Todo.find(params[:id])`で`id`が`1`だったら取得するデータをbyebugというデバッグツールで確認してみると
`#<Todo id: 1, title: "テスト", created_at: "2019-10-18 04:05:36", updated_at: "2019-10-18 04:05:36">`

というデータが取れます。


### ここで注意点

教えていて勘違いしている方が多かったので補足。

今回`title`カラムのデータを取得したいわけです。
`@todo = Todo.find(params[:id])`をすると`title`のデータ`だけ`を取得しているのではありません。意図的にデータを絞り込まなければ、今回の場合
`id`, `title`, `created_at`, `updated_at` 1レコード(1行)分のデータ取得されます。


`@todo = Todo.find(params[:id])` idは1とすると

正：
`#<Todo id: 1, title: "テスト", created_at: "2019-10-18 04:05:36", updated_at: "2019-10-18 04:05:36">`

誤：
`#<Todo title: "テスト">`

自分が必要だと思っているデータだけ取得できてると勘違いしている？？ように思えましたので補足。


こらへんはSQLを理解していないから起こることなのかとも思います。
気を付けましょう。

### 更新処理アクション追加

ルーティングとコントローラーに追記していきます。
resources使うともう少しシンプルに書けますが、今回は原理を知るためしっかりと書いていきます。

```routes.rb
Rails.application.routes.draw do
  get '/todos', to: 'todos#index', as: 'todos'
  post '/todos', to: 'todos#create'
  
  get '/todos/:id/edit', to: 'todos#edit', as: 'edit_todo'
  patch '/todos/:id', to: 'todos#update' # 更新処理用ルーティング追加
end
```


````app/controllers/todos_controller.rb
  def update
    @todo = Todo.find(params[:id])
    @todo.update(todo_params)
    redirect_to todos_path
  end
```

resouses使えるならこんな感じでシンプルに書ける

```.erb
<-- resousesを使えるときなら -->
<h1>ToDo編集</h1>
<%= form_with model: @todo do |f| %>
  <div><%= f.label :title %></div>
  <div><%= f.text_field :title %></div>
  <div><%= f.submit %></div>
<% end %>
<%= link_to '戻る', todos_path %>
```

今回原理をよく理解するためにこのようにURLとメソッドもちゃんと書きました。
`#{ }`は文字列として変数を埋め込めるRubyの記法です。
変更するToDoデータの`id`を指定すれば同じことを行えます。

```.erb:edit.html.erb
<h1>ToDo編集</h1>
<%= form_with(model: @todo, url: "/todos/#{@todo.id}", method: :patch) do |f| %>
  <div><%= f.label :title %></div>
  <div><%= f.text_field :title %></div>
  <div><%= f.submit %></div>
<% end %>
<%= link_to '戻る', todos_path %>
```


### 編集ページへのリンクを作る

変更箇所付近だけ抜粋。`link_to`と`~~~~_path`を使ってやるとこんな風に簡単に作れる。


```.erb:index.html.erb
<% @todos.each do |todo| %>
  <tr>
    <td><%= todo.title %></td>
    <td><%= link_to '編集', edit_todo_path(todo) %></td>
  </tr>
<% end %>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/4aea333f-90ef-f433-083b-82ea3461eb10.png)


```.erb
<td><%= link_to '編集', edit_todo_path(todo.id) %></td>
```



ついでに、ちゃんと省略して書かないとこういう書き方になる。`todo` → `todo.id`
Railsがいい感じで判断してくれるのでこのようになりますが、原理は覚えておくほうがいいと思います。
htmlだと↓のようなものが作られる
`<a href="/todos/1/edit">編集</a>`

## 削除機能実装
削除機能はわかってしまえば他と大して変わらないので楽です。
1. ルーティング追加
2. コントローラーに`destroy`アクション追加
3. ビューに削除ボタンのリンク追加



```routes.rb
Rails.application.routes.draw do
  get '/todos', to: 'todos#index', as: 'todos'
  post '/todos', to: 'todos#create'
  
  get '/todos/:id/edit', to: 'todos#edit', as: 'edit_todo'
  patch '/todos/:id', to: 'todos#update'
  delete '/todos/:id', to: 'todos#destroy'
end
```


- `@todo = Todo.find(params[:id])`で削除する項目(idで指定された項目)を@todoに入れる
- destroyメソッドで削除する
- 元のページに戻る

```app/controllers/todos_controller.rb
  def destroy
    @todo = Todo.find(params[:id])
    @todo.destroy
    redirect_to todos_path
  end
```

`<td><%= link_to '削除', "/todos/#{todo.id}", method: :delete %></td>`を追加。
`method: :delete`でメソッドを指定。（指定しないとデフォルトのGETになります。）
ルーティングでdeleteに設定したURLは`delete '/todos/:id', to: 'todos#destroy'`なので対応させるために`"/todos/#{todo.id}"`このように書きました。


```.erb:index.html.erb
<% @todos.each do |todo| %>
  <tr>
    <td><%= todo.title %></td>
    <td><%= link_to '編集', edit_todo_path(todo) %></td>
    <td><%= link_to '削除', "/todos/#{todo.id}", method: :delete %></td>
  </tr>
<% end %>
```
削除機能が完成しました。

![todo3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260345/a04c517e-eeaa-69c5-6b78-b64ae5a41d04.gif)

見た目は最悪ですが、ToDo登録・更新・削除機能が完成しました。