【Rails入門】エラーと仲良くなれるかもしれない開発手法【読み物】

どんもー、[@snskOgata](https://twitter.com/snskOgata)です。

今回はみんな大好き、エラーとの付き合い方を書いていこうかなと思います。
まあ、ちょっとした読み物として楽しんでもらえたらと思います。
　
　
対象読者は以下の2つに当てはまる人です。
**・エラーという存在が憎くて憎くてしょうがない
・Railsアプリを読み物を見ながら1, 2度作ってみたけど、実際に自分で何も見ずに作るとなったらどうやっていけばいいかわからない**
　
エラーが出るとどうしても怒られているような感覚になってしまいますが、
そうじゃなくて本当は、**エラーは正解への道筋を示してくれる相棒**のようなものだということを感じてくれると嬉しいです。

 
　
実際やっていくこととしては、
**エラーを吐かせながら、それに従ってアプリケーションを作っていく**ということをしていきます。
これによりひとつずつ着実に作業を進めることができます。
アプリの内容は、つぶやきを作成しその一覧を表示する簡単なアプリケーションです。
途中で大体もう流れがわかったら最後まで飛ばしてくれても大丈夫です(笑)

# 1. Setup
まずはアプリケーションをビルドします。
Railsバージョンは5.2.3を使用します

```
$ rails _5.2.3_ new dev-with-error
$ cd dev-with-error
$ bundle
$ rails db:migrate
```

やってることはRailsアプリケーションを立ち上げ、フォルダを移動して、gemファイルのインストール、DBの作成です。
ここまでやるとローカルサーバを立ち上げることができます。

```
$ rails s
```
Webブラウザで「localhost:3000」にアクセスすればお馴染みの画面が出てきます。
<img width="1440" alt="スクリーンショット 2020-01-12 18.02.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558820/ad955ee7-127b-d2e1-8424-a4538a88ff6b.png">

# 2.Tweet作成画面を作る
次にTweetの新規作成画面を作っていきたいと思います。
ここで通常であれば、ルーティングをして、コントローラとモデルを作って、適切なビューを作って...とやっていくと思いますが、
今回は冒頭でも書いたように**まずはエラーを吐かせてそれに従って作っていく**というふうに作って行きます。

実際にやることとしては、Tweetの新規作成画面ということで「localhost:3000/tweets/new」というアドレスにアクセスをします
<img width="1426" alt="スクリーンショット 2020-01-12 18.10.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558820/43a931ce-6195-9e8c-a43f-3969f70e5ab8.png">
まだアプリケーション本体に何も書き込んでいないわけなので当然エラーを吐かれます。
エラーの内容を見てみると、ルーティングがされていないよ！とのエラーが出ているので、実際にルーティング部分を書き加えます。

```config/routes.rb
Rails.application.routes.draw do
  resources :tweets, only: :new
end
```
もう一度先ほどのURLにアクセスすると次はこのようなエラーが出ます。<img width="1426" alt="スクリーンショット 2020-01-12 18.16.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558820/e7ea6078-4514-ab08-d35d-bd34a1308112.png">
今度はTweetsControllerがないのでそれを教えてくれます。
エラーに従ってコントローラを作成しましょう。

```
$ rails g controller tweets
```
<img width="1427" alt="スクリーンショット 2020-01-12 18.18.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558820/b0e2abac-6ebb-9461-028e-0f72ecd55cda.png">

newアクションが見つからないということでTweetsControllerに追記します。

```app/controllers/tweets_controller.rb
class TweetsController < ApplicationController
  def new
  end
end
```

保存をし再びページをリロードすると、
<img width="1424" alt="スクリーンショット 2020-01-12 18.23.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558820/b195f6d4-1eab-0755-95c4-5cc754474182.png">
随分長いエラー文となっていますが、冒頭の「**TweetsController#new is missing a template**」から、newアクションに対応するビューのテンプレートがないというのがエラーの原因というのがわかります。
なので、Tweets#newに対応するように、「views/tweets/new.html.erb」を作成します。

```app/views/tweets/new.html.erb
Hello
```
「localhost:3000/tweets/new」にアクセスすると、
<img width="356" alt="スクリーンショット 2020-01-12 18.29.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558820/c0468c94-3472-e5de-4d6e-cc679fb8ed7e.png">
おめでとう！これで新規作成画面の表示に成功しました！

さて、新規投稿するためにインスタンス変数@&#x200b;tweetを用意しましょう。

```app/controllers/tweets_controller.rb
class TweetsController < ApplicationController
  def new
    @tweet = Tweet.new
  end
end
```
ここで再びページリロードをすると
<img width="1425" alt="スクリーンショット 2020-01-12 18.34.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558820/8357ddca-e32b-a092-8443-daa9ca510187.png">
Tweetというものがわからない！と言われるので、Tweetモデルを作成してあげます

```
$ rails g model tweet content:string
...
```
モデルが生成されましたが
<img width="1428" alt="スクリーンショット 2020-01-12 18.38.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558820/b163d45d-6127-85d0-d3c4-109439563b3f.png">
問題を解決するには「rails db:migrate」して、と書かれています。
どうやらマイグレーションファイルをDBに適用していないのが問題みたいです。

```
$ rails db:migrate
```
これで再びエラー無しの状態になりました！
次に、実際にビューに今回用意したインスタンス変数を使って、フォームを作成してみます。

```erb:app/views/tweets/new.html.erb
<%= form_with model: @tweet do |form| %>
  <%= form.text_field :content %>
  <%= form.submit %>
<% end %>
```
ここでのエラーはわかりづらいですが、form_withによってtweets_pathにポストがなされるのですが、そのメソッド(:create)が宣言されていないためにのエラーとなります。
<img width="1423" alt="スクリーンショット 2020-01-12 18.45.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558820/deba3abb-3189-b6eb-268a-0d5c85ba52b9.png">
ルーティングで「:create」を追加してあげましょう。

```config/routes.rb
Rails.application.routes.draw do
  resources :tweets, only: [:new, :create]
end
```
再びエラー無しに！
<img width="222" alt="スクリーンショット 2020-01-12 18.51.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558820/0e4b3b10-95ab-3e26-7ee3-e81668cc4314.png">
ただしcreateアクションを実際に実装していないため、フォームを入力しても何も変わりません。
なのでコントローラにcreateを追記してあげましょう。
ついでに新規投稿画面に、投稿された一覧を表示できるようにしましょう。

```app/controllers/tweets_controller.rb
class TweetsController < ApplicationController
  def new
    @tweet = Tweet.new
    @tweets = Tweet.all #追記：全投稿取得→表示に使用
  end

  def create
    Tweet.create(tweet_params) # DBに保存
    redirect_to new_tweet_path # 新規投稿画面に再び戻る
  end

  private
    # ストロングパラメータ
    def tweet_params
      params.require(:tweet).permit(:content)
    end
end
```

```erb:app/views/tweets/new.html.erb
<% # local: trueにすることで、送信後ページが更新される %> 
<%= form_with model: @tweet, local: true do |form| #local %>
  <%= form.text_field :content %>
  <%= form.submit %>
<% end %>

<p>Tweets</p>
<% # Tweetの一覧表示 %> 
<%- @tweets.each do |tweet| %>
  <%= "#{tweet.content} <#{tweet.created_at}>" %>
  <br/>
<% end %>
```
無事、簡単なつぶやき投稿アプリができました！
<img width="503" alt="スクリーンショット 2020-01-12 20.44.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558820/9a2c88a0-1855-bf18-543b-100d414930b1.png">

同様にして編集ページや一覧表示ページ、あるいは新しいコントローラやモデルを作成していけば、ある程度のものであればエラーに従っていくだけで作れてしまうと思います！

# 3. 一気にRMVCを作ってしまう弊害
この手法だとエラーに従ってひとつずつパーツを揃えていくため、今コーディングしている部分が正しくなければ先に進むことができません。
すなわち、エラー部分が限定されて**間違っている可能性がある部分というのがすごく限定的**になります。

Railsを始めたての人は、MVCを一度に実装してしまったために、エラーが発生したときに何処で起きているのかがわからなくなってしまう、という問題に遭遇してる人が多い様な気がします。
なので、こういうように着実に進められる方法もあるよ、エラーは怒ってるんじゃなくて導いてくれてるんだよ、ってのを少しでも実感してくれたら幸いです。

# 4.テスト駆動開発
こういう開発手法を思いついたきっかけがテスト駆動開発(TDD)です。
この手法は、今回エラーを起こして進めて行ったような感じで、まずは通らないテストを書いて、それに通るように実装をしていくという手法です。
実際の現場でも使われている手法で[^1]、一度は経験しておいて損はないかなと思います。
読みながらならある程度簡単なアプリなら作り方が理解できる方なら、Rails Tutorialという本が無料で公開されているので挑戦してみると良いかもしれません。（※Rails Tutorialはminitestというデフォルトのテストを用いているのでRSpecを使ってる方は違いには注意！）
Rails Tutorial：https://railstutorial.jp/chapters/beginning?version=5.1#cha-beginning

加えてここではgem(deviseなど)を使わずにユーザ管理を実装するのですが、Deviseの作者も一度は自分の手でUserモデルを作成することを推奨しているので、その点でもオススメです。

追記：ついでにHerokuで簡単にデプロイする方法とか、自作ヘルパーメソッドの実装とかもすごくタメになります！



[^1]: 実際はコストの面との相談で使われなかったりする？ テスト自体は非常に重要なことには変わりないですが！