ザコアプリを作ってform_forを学んでみた
railsをはじめて1ヶ月。作るアプリは徐々に複雑になってきはじめ、曖昧な知識達を複数組み合わせる機会が増えました。
私の理解は既に空中分解しかけており、原点を見失いそうになりつつある状況です。
そこで、原点に立ち返ろうと思い「ザコアプリ」を作ることで曖昧な知識のひとつ「form_for」やその周辺知識を整理して理解しようじゃないかと思ったのが本記事を書いた動機です。
今回作るザコアプリ
この記事内容をまんま真似していくことで、下のザコアプリを生成することができます。
フォームに入力して投稿するボタンを押すと
投稿内容が反映されます。
rails のファイル一式を作る
サクサク作っていきます。まずはターミナルを開きrailsのファイル一式を作ります。
使用したコマンドはこちらです。
$ mkdir zako_app
$ cd zako_app
$ rails new zako
mkdirコマンドで新規フォルダ「zako_app」を作成し、rails newコマンドで新規rails アプリ「zako」を作成しています。これでzakoのrailsファイル一式が生成されました。
テキストエディタの「sublime_text」でフォルダ一式開きました。今回はこのエディタで作っていきます。
ルーティングを設定する
今回は「articles」と自分で名付けて、resourcesを用いてルーティングを自動設定しました。また、ルートは現状articlesのnewアクションとして設定しておきました。
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
コントローラーの中にアクションを定義します。今回は「newアクション」を取り急ぎ、空で配置しておきました。
newアクションに対応するnewビューを生成する
newアクションを定義したので、そのnewアクションに対応するビューを生成します。ここは単純にviews/articles内に右クリックで生成→保存します。
new.html.erbと名付け保存しました。この中に「私はnewのビューです。」と書き、$rails s
コマンドでサーバーを立ち上げ、実際に表示されるかを開いてみます。
ターミナルで$rails s
コマンドを叩き、サーバーを立ち上げます。
$rails s
ローカルホストhttp://localhost:3000/を開いたときに「私はnewのビューです。」と表示されれば、とりあえずルーティング→コントローラー→ビューへの表示という基本の流れの設定は成功です。
new.html.erbにform_forを用いてフォーム画面を書いていきますが、ユーザーがフォームに入力した内容を保存する「データベース」を用意しなければフォームは機能しないので、先にデータベースを用意します。
Articleモデルとそれに対応するデータベースを生成する
フォームを機能させるにはコントローラーとデータベース間でやりとりができるようにしなければなりません。
ここまでで生成した「articlesビュー」と「articlesコントローラー」に紐づく「Articleモデル」を生成することで、コントローラーとデータベース間でのやりとりが可能になります。
Articleモデルを生成する
ターミナルで下記コマンドを入力し、Articleモデルを生成します。このとき、Articlesと複数形にならないように注意します。
- コントローラ名:→複数形
- モデル名 :→単数形
とすることで、自動的に対応関係が築かれるようにrailsではなっています。
$ rails g model Article
これにより下記のようなmodels/article.rbというモデルが生成されました。
中の記述を読んでみると、application_record.rb内の「AplicationRecord」クラス内にある「ActiveRecord::Base」がArticleクラスに継承されていることがわかります。これによりデータベースと連携されるようになります。
articlesテーブルを生成する
Articleモデルを生成した後にdb/migrate/内を見てみると下図のような「日時_create_articles.rb」というマイグレーションファイルが生成されます。
これは「どのようなarticlesテーブルを作るか?」の設計書的な存在のもので、ターミナルでrake db:migrate
のコマンドを実行することで、この内容に基づいたテーブルが生成されます。
今回は、フォームの中で「タイトル」と「テキスト」という枠を設けたいので、それぞれに対応したテーブルのカラム(列)が作られるようこの中に項目を追加で書いていきます。
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テーブル」が生成されています。
※データベースの中身はDB Browser for SQLiteというアプリケーションを用いることで、視覚的に確認することもできます。
上部の「Open Data Base」から「db/migrate/development.sqlite3」を指定し、「articles」テーブルを選択すると確認できます。
「form_for」を使ってフォームを作成する
ここまででデータベースの用意もできたので、form_forメソッドを用いてnew.html.erbにフォームを書いていきます。
まず、form_forメソッドをnewビュー内で用いるためのモデルオブジェクト(@article
)をコントローラー内で設定しておきます。
def new
@article = Article.new
end
つぎに、newビュー内にform_forメソッドを用いたフォームの基本形を作ります。rubyコードを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ボタンを作ります。
これで、このようなフォームが作成できます。
また、form_forのsubmitを押した時の挙動ですが
-
@article
が新規作成された時はarticlesコントローラーのcreateアクションへ -
@article
が既存で存在している場合はarticlesコントローラーのupdateアクションへ
と自動でform_forメソッドがアクションを振り分けてくれます。よって、「create」「update」のアクションを使用するにはそれぞれコントローラ内で定義する必要があります。
これをベースに少し変更します。具体的には、submitを押したときのアクションを指定したり、フォームのラベルを付けたり、submitボタンの表示文言を変更したりします。
<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, "タイトル"
「タイトル」というラベルを作ります。
これで下図のようなフォームが作れます。
現時点では、submitを押したときに実行されるcreateアクションが設定されていないので、入力してもエラーになります。
createアクションを設定する
フォームに入力した内容をarticlesテーブルに保存するための「createアクション」をarticlesコントローラー内で設定します。
paramsの内容を確認する
createアクションが実行されたタイミングでどのようなパラメータが飛んできているのかを確認するために、raise.params.inspect
をcreateアクションに設定して実行し、意図的にエラーを起こします。
def create
raise.params.inspect
end
下のparameters:のところで、createアクションが実行されたタイミングで飛んできているパラメータを確認することができます。
"article"=>{"title"=>"これはテストです。", "text"=>"ここに内容を入力します。"},
この中のtitleとtextに対応するバリューがフォームで入力した内容です。
コントローラーにcreateを設定する
上記の2つをそれぞれテーブルに安全に保存したいので、下記のように書きました。
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以下に記載することで安全面も考慮しています。
上記のようにコントローラを設定して、投稿するとデータベースにしっかり保存されていることが確認できました。
↓
showアクションとshowビューを設定して入力内容を表示されるようにする
今のままだと、createされたあとに微動だにしません。
入力した内容が表示されるように、showアクションとそれに対応するshowビューを設定し、createアクションが実行された後にはshowアクションが実行されるようにします。
showアクションの設定
def show
@article = Article.find(params[:id])
end
articlesテーブル内からcreateアクションで生成したレコードを取得し、それをビュー内で使えるインスタンス変数(@article
)に入れました。
@に入れることでビュー(show.html.erb)内でもこの変数を使えるようになります。
showビューの作成
newビューと同様に右クリックで作成し、保存することでshowビュー(show.html.erb)を生成します。
ビュー内には下記のように書くことで@article
内のフォームで入力した内容をそれぞれ表示します。
<h1><%= @article.title %></h1>
<p><%= @article.text %></h1><br>
<%= link_to "入力フォームに戻る", new_article_path %>
また、入力フォームに戻れるようにlink_toメソッドを用いてnewアクションへのリンクも生成します。
createアクションの遷移設定
createアクションが実行された後にはcreateビューを表示するのではなく、showアクションが実行されるようにredirect_toメソッドを用いて設定します。
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になります。
完成
本当は編集機能も付けたいですが、長くなったのでこちらでザコアプリ完成ということで区切りたいと思います。
フォームに入力して投稿するボタンを押すと
投稿内容が反映されます。
完成ソースコード
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
<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 %>
<h1><%= @article.title %></h1>
<p><%= @article.text %></h1><br>
<%= link_to "入力フォームに戻る", new_article_path %>