【Rails】form_forメソッドを用いたザコアプリ作成

# ザコアプリを作ってform_forを学んでみた
railsをはじめて１ヶ月。作るアプリは徐々に複雑になってきはじめ、曖昧な知識達を複数組み合わせる機会が増えました。

私の理解は既に空中分解しかけており、原点を見失いそうになりつつある状況です。
そこで、原点に立ち返ろうと思い「ザコアプリ」を作ることで曖昧な知識のひとつ「form_for」やその周辺知識を整理して理解しようじゃないかと思ったのが本記事を書いた動機です。
# 今回作るザコアプリ
この記事内容をまんま真似していくことで、下のザコアプリを生成することができます。
><img width="237" alt="スクリーンショット 2017-05-11 20.33.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/211b36ce-a44a-bfa6-06e1-839ff0937359.png">

フォームに入力して投稿するボタンを押すと
><img width="353" alt="スクリーンショット 2017-05-11 20.33.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/31c29024-15de-b417-6f64-dbc7d2f11f3d.png">

投稿内容が反映されます。
# rails のファイル一式を作る
サクサク作っていきます。まずはターミナルを開きrailsのファイル一式を作ります。
使用したコマンドはこちらです。

```
$ mkdir zako_app
$ cd zako_app
$ rails new zako
```
mkdirコマンドで新規フォルダ「zako_app」を作成し、rails newコマンドで新規rails アプリ「zako」を作成しています。これでzakoのrailsファイル一式が生成されました。
<img width="438" alt="スクリーンショット 2017-05-11 12.51.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/3a78b801-afdf-885a-334d-1318776f8e42.png">
テキストエディタの「sublime_text」でフォルダ一式開きました。今回はこのエディタで作っていきます。
<img width="1178" alt="スクリーンショット 2017-05-11 12.52.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/b26cdb67-2e39-bfee-af96-b12922cd8302.png">
# ルーティングを設定する
今回は「articles」と自分で名付けて、resourcesを用いてルーティングを自動設定しました。また、ルートは現状articlesのnewアクションとして設定しておきました。

```config/routes.rb
Rails.application.routes.draw do
  root 'articles#new'
  resources :articles
end
```
一応、このタイミングで生成されたルーティングを`$rake routes`で確認しておきます。
下記のようにルーティングが設定されたことを確認します。

```
$rake routes
```
```
$ bundle exec rake routes
      Prefix Verb   URI Pattern                  Controller#Action
    articles GET    /articles(.:format)          articles#index
             POST   /articles(.:format)          articles#create
 new_article GET    /articles/new(.:format)      articles#new
edit_article GET    /articles/:id/edit(.:format) articles#edit
     article GET    /articles/:id(.:format)      articles#show
             PATCH  /articles/:id(.:format)      articles#update
             PUT    /articles/:id(.:format)      articles#update
             DELETE /articles/:id(.:format)      articles#destroy
```
# コントローラーを生成し、newアクションを定義する
これに対応するarticlesコントローラーを下記コマンドで生成します。

```
$ rails g controller articles
```
これでarticlesコントローラーが生成されました。
<img width="695" alt="スクリーンショット 2017-05-11 13.17.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/26f448ea-5c89-1b76-6393-fdf475bfed17.png">

コントローラーの中にアクションを定義します。今回は「newアクション」を取り急ぎ、空で配置しておきました。
<img width="691" alt="スクリーンショット 2017-05-11 13.29.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/863f1c3c-f0e8-02c8-401e-fa215914f566.png">
# newアクションに対応するnewビューを生成する
newアクションを定義したので、そのnewアクションに対応するビューを生成します。ここは単純にviews/articles内に右クリックで生成→保存します。
<img width="231" alt="スクリーンショット 2017-05-11 13.33.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/9b00987d-1d27-d5bc-3876-b373c1d4e414.png"><img width="417" alt="スクリーンショット 2017-05-11 13.35.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/2aa67e3c-eea6-64dd-bb76-2045ed3bb43c.png">
new.html.erbと名付け保存しました。この中に「私はnewのビューです。」と書き、`$rails s`コマンドでサーバーを立ち上げ、実際に表示されるかを開いてみます。
<img width="742" alt="スクリーンショット 2017-05-11 13.36.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/5dcc938d-cdb7-ab9e-7f76-a880265198fb.png">
ターミナルで`$rails s`コマンドを叩き、サーバーを立ち上げます。

```
$rails s
```

ローカルホスト[http://localhost:3000/](http://localhost:3000/)を開いたときに「私はnewのビューです。」と表示されれば、とりあえずルーティング→コントローラー→ビューへの表示という基本の流れの設定は成功です。
><img width="461" alt="スクリーンショット 2017-05-11 13.47.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/563a48a5-b080-8c07-36af-8ccbbcf8d9e8.png">

new.html.erbにform_forを用いてフォーム画面を書いていきますが、ユーザーがフォームに入力した内容を保存する「データベース」を用意しなければフォームは機能しないので、先にデータベースを用意します。
# Articleモデルとそれに対応するデータベースを生成する
フォームを機能させるにはコントローラーとデータベース間でやりとりができるようにしなければなりません。
ここまでで生成した「articlesビュー」と「articlesコントローラー」に紐づく「Articleモデル」を生成することで、コントローラーとデータベース間でのやりとりが可能になります。
## Articleモデルを生成する
ターミナルで下記コマンドを入力し、Articleモデルを生成します。このとき、Articlesと複数形にならないように注意します。

- コントローラ名：→複数形
- モデル名　　　：→単数形

とすることで、自動的に対応関係が築かれるようにrailsではなっています。

```
$ rails g model Article
```
これにより下記のようなmodels/article.rbというモデルが生成されました。
<img width="663" alt="スクリーンショット 2017-05-11 14.28.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/d8d8bee8-9c3c-1210-0798-58c33ead1fcc.png">
中の記述を読んでみると、application_record.rb内の「AplicationRecord」クラス内にある「ActiveRecord::Base」がArticleクラスに継承されていることがわかります。これによりデータベースと連携されるようになります。
## articlesテーブルを生成する
Articleモデルを生成した後にdb/migrate/内を見てみると下図のような「日時_create_articles.rb」というマイグレーションファイルが生成されます。
<img width="765" alt="スクリーンショット 2017-05-11 15.07.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/72148938-55aa-e4d6-53ed-78fd70f7bdad.png">
これは「どのようなarticlesテーブルを作るか？」の設計書的な存在のもので、ターミナルで`rake db:migrate`のコマンドを実行することで、この内容に基づいたテーブルが生成されます。

今回は、フォームの中で「タイトル」と「テキスト」という枠を設けたいので、それぞれに対応したテーブルのカラム（列）が作られるようこの中に項目を追加で書いていきます。

```db/migrate/20170511052306_create_articles.rb
class CreateArticles < ActiveRecord::Migration[5.0]
  def change
    create_table :articles do |t|
      t.string :title
      t.text :text
      t.timestamps
    end
  end
```
書き終えたら、ターミナル内で下記コマンドを実行します。

```
$ rake db:migrate
```
これにより「db/migrate/development.sqlite3」内に「articlesテーブル」が生成されています。
<img width="275" alt="スクリーンショット 2017-05-11 15.30.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/b1237f61-8fc8-1193-f8a9-de16bdbd505b.png">

※データベースの中身は[DB Browser for SQLite](http://sqlitebrowser.org/)というアプリケーションを用いることで、視覚的に確認することもできます。<img width="1067" alt="スクリーンショット 2017-05-11 15.40.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/7b89ceaa-8a72-e680-9833-6f388fd94684.png">
上部の「Open Data Base」から「db/migrate/development.sqlite3」を指定し、「articles」テーブルを選択すると確認できます。

# 「form_for」を使ってフォームを作成する
ここまででデータベースの用意もできたので、form_forメソッドを用いてnew.html.erbにフォームを書いていきます。
まず、form_forメソッドをnewビュー内で用いるためのモデルオブジェクト（`@article`）をコントローラー内で設定しておきます。

```articles_controller.rb
  def new
    @article = Article.new
  end
```

つぎに、newビュー内にform_forメソッドを用いたフォームの基本形を作ります。rubyコードをhtmlに反映させるのでerb記法で書いていきます。

```new.html.erb
<%= form_for @article do |f| %>
  <%= f.text_field :title %><br>
  <%= f.text_area :text %><br>
  <%= f.submit %>
<% end %>
```
- `f.text_field`
一行のテキストを入力するためのフォームを作ります。
- `f.text_area`
複数行のテキストを入力するためのフォームを作ります。
- `f.text_submit`
submitボタンを作ります。

これで、このようなフォームが作成できます。
><img width="165" alt="スクリーンショット 2017-05-11 17.30.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/221705a1-166e-7546-7dc3-d8e87abad1f6.png">

また、form_forのsubmitを押した時の挙動ですが

- **`@article`が新規作成された時はarticlesコントローラーのcreateアクション**へ
- **`@article`が既存で存在している場合はarticlesコントローラーのupdateアクション**へ

と自動でform_forメソッドがアクションを振り分けてくれます。よって、**「create」「update」のアクションを使用するにはそれぞれコントローラ内で定義する必要があります。**

これをベースに少し変更します。具体的には、submitを押したときのアクションを指定したり、フォームのラベルを付けたり、submitボタンの表示文言を変更したりします。

```new.html.erb
<h1>投稿フォーム</h1>
<%= form_for @article, url: articles_path do |f| %>
  <p>
    <%= f.label :title, "タイトル" %><br>
    <%= f.text_field :title %>
  </p>
  <p>
    <%= f.label :text, "内容" %><br>
    <%= f.text_area :text %>
  </p>
  <p>
    <%= f.submit "投稿する"%>
  </p>
<% end %>
```
- `url: articles_path`
submitを押した時の飛び先を指定することができます。
- `f.label :title, "タイトル"`
「タイトル」というラベルを作ります。

これで下図のようなフォームが作れます。
><img width="243" alt="スクリーンショット 2017-05-11 18.04.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/a0f52213-d8c5-54ba-48f5-5aadbf9fc106.png">

現時点では、submitを押したときに実行されるcreateアクションが設定されていないので、入力してもエラーになります。
# createアクションを設定する
フォームに入力した内容をarticlesテーブルに保存するための「createアクション」をarticlesコントローラー内で設定します。
### paramsの内容を確認する
createアクションが実行されたタイミングでどのようなパラメータが飛んできているのかを確認するために、`raise.params.inspect`をcreateアクションに設定して実行し、意図的にエラーを起こします。

```articles_controller.rb
  def create
    raise.params.inspect
  end
```
<img width="745" alt="スクリーンショット 2017-05-11 18.22.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/48df600a-a271-8855-77ce-549dea963864.png">
下のparameters:のところで、createアクションが実行されたタイミングで飛んできているパラメータを確認することができます。

```
 "article"=>{"title"=>"これはテストです。", "text"=>"ここに内容を入力します。"},
```
この中のtitleとtextに対応するバリューがフォームで入力した内容です。
### コントローラーにcreateを設定する
上記の２つをそれぞれテーブルに安全に保存したいので、下記のように書きました。

```articles_controller.rb
  def create
    @article = Article.create(article_params)
  end

  private
  def article_params
    params.require(:article).permit(:title, :text)
  end
```
***article_paramsについて***
requireメソッドを使ってキーがarticleのバリューの`{"title"=>"これはテストです。", "text"=>"ここに内容を入力します。"}`を取得しています。
そしてpermitメソッドを使いtitleとtextをキーとするハッシュ(フォームで入力した内容)を取得しています。private以下に記載することで安全面も考慮しています。

上記のようにコントローラを設定して、投稿するとデータベースにしっかり保存されていることが確認できました。
<img width="174" alt="スクリーンショット 2017-05-11 19.05.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/8812718d-c137-62af-12ef-1142c638f0c8.png">
↓
<img width="538" alt="スクリーンショット 2017-05-11 19.05.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/b624fd44-fe80-6212-8e88-733d1e19f53f.png">
# showアクションとshowビューを設定して入力内容を表示されるようにする
今のままだと、createされたあとに微動だにしません。
入力した内容が表示されるように、showアクションとそれに対応するshowビューを設定し、createアクションが実行された後にはshowアクションが実行されるようにします。
### showアクションの設定
```articles_controller.rb
  def show
    @article = Article.find(params[:id])
  end
```
articlesテーブル内からcreateアクションで生成したレコードを取得し、それをビュー内で使えるインスタンス変数（`@article`）に入れました。
***@に入れることでビュー(show.html.erb)内でもこの変数を使えるようになります。***

### showビューの作成
newビューと同様に右クリックで作成し、保存することでshowビュー(show.html.erb)を生成します。
<img width="417" alt="スクリーンショット 2017-05-11 19.11.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/495f32ba-ac2c-f3c8-0c17-ff98858150ec.png">

ビュー内には下記のように書くことで`@article`内のフォームで入力した内容をそれぞれ表示します。

```show.html.erb
<h1><%= @article.title %></h1>
<p><%= @article.text %></h1><br>
<%= link_to "入力フォームに戻る", new_article_path %>
```
また、入力フォームに戻れるようにlink_toメソッドを用いてnewアクションへのリンクも生成します。

### createアクションの遷移設定
createアクションが実行された後にはcreateビューを表示するのではなく、showアクションが実行されるようにredirect_toメソッドを用いて設定します。

```articles_controller.rb
  def create
    @article = Article.create(article_params)
    redirect_to article_path(@article)
  end
```
redirect_toメソッドによってshowアクション(=article_path)が実行されるようにしています。
その際に_pathメソッドの引数に`@article`を渡すことで、URLに生成したarticleのidをパラメータ付与することができます。

例）初めての投稿の場合
`http://localhost:3000/articles/1`
というようなURLになります。

# 完成
本当は編集機能も付けたいですが、長くなったのでこちらでザコアプリ完成ということで区切りたいと思います。
><img width="237" alt="スクリーンショット 2017-05-11 20.33.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/211b36ce-a44a-bfa6-06e1-839ff0937359.png">

フォームに入力して投稿するボタンを押すと
><img width="353" alt="スクリーンショット 2017-05-11 20.33.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/179510/31c29024-15de-b417-6f64-dbc7d2f11f3d.png">

投稿内容が反映されます。
## 完成ソースコード
```articles_controller.rb
class ArticlesController < ApplicationController

  def new
    @article = Article.new
  end

  def show
    @article = Article.find(params[:id])
  end

  def create
    @article = Article.create(article_params)
    redirect_to article_path(@article)
  end

  private
  def article_params
    params.require(:article).permit(:title, :text)
  end
end
```

```new.html.erb
<h1>投稿フォーム</h1>
<%= form_for @article, url: articles_path do |f| %>
  <p>
    <%= f.label :title, "タイトル" %><br>
    <%= f.text_field :title %>
  </p>
  <p>
    <%= f.label :text, "内容" %><br>
    <%= f.text_area :text %>
  </p>
  <p>
    <%= f.submit "投稿する"%>
  </p>
<% end %>
```

```show.html.erb
<h1><%= @article.title %></h1>
<p><%= @article.text %></h1><br>
<%= link_to "入力フォームに戻る", new_article_path %>
```