5.アプリケーションの実装と実行
ハローワールドしたということは、開発環境が整ったということ。
これからがしがし実装していくぞ!
ということでもっとブログっぽくしていくって。
ブログといえば記事をかいて投稿してそれをきた人に見てもらう。
僕のブログはまだHello,Rails!しか表示できない。
こんなんブログと言えるか!
「今度はBlogアプリケーションに新しくリソースを作成します。ここで言う「リソース」とは、記事、人、動物などのよく似たオブジェクト同士が集まったものを指します。 リソースに対して作成 (create)、読み出し (read)、更新 (update)、削除 (destroy) の4つの操作を行なうことができるようになっており、これらの操作の頭文字を取ってCRUDと呼ばれます。」
CRUDはよく使われる言葉です。
例えば記事というデータに対して僕らが行うのは、記事の作成(create)、投稿した記事の表示(read)、投稿した記事の修正(update)、そして黒歴史の削除(destroy)ですね。(僕が昔作ったポエムは是非ともデストロイしたい)
リソースってなんだろう?
CRUDをする対象って言っているから、おそらくデータに関わるものなんだろう。
↓のようにroutes.rbに追記することによってarticlesというリソースへのルーティングができたことになるらしい。(やっぱりroutes.rbって重要な設定ファイルだよな)
Rails.application.routes.draw do
get 'welcome/index'
resources :articles
root 'welcome#index'
end
IT業界で働く人にとってはデータっていうとデータベースの中に入っていて、そこからSQLをもちいてデータをSELECTしたり、INSERTしたり、UPDATEしたり、DELETEしたり、複雑なデータだったらJOINとかして引っ張ってきてアプリの方でなんか画面表示に使ったりフラグの判定に使ったりするけど、あれ? Railsではデータベースって使わないの? SQLite3はインストールしたよなあ。
routes.rbにresourcesって書くだけでデータが使えるようになるの?
え、それってすごく便利じゃね?そんなうまい話はないやろー
んー? どういうことなんだろう。もうちょっと進めればわかるかな。
ちなみに以下のコマンドで今のルーティングが確認できるって。
$bin/rails routes
さっき僕が追加したwelcomeコントローラくんがいるよね。
Prefixはあとあと使う機会がありそう(Railsのコード書く時に、Prefix_pathってかけばそのアクションのパスを指定できるらしい)
Verbはリクエストの種類でGET、POST、PATCH、PUT、DELETEなどがあるよ。welcome/indexはGETリクエストだね。(これも後々…)
URI Patternがブラウザ上に打ち込む文字列だ。さっきは(http://localhost:3000/welcome/index) というURLでHello,Rails!が表示できた。
Controller#ActionがURI Patternを打った時の仕事をするコントローラとそのアクション(つまりページを表示するビュー)になる。
routesの設定の見方はこんな感じ。
話を戻そう。
resources :articlesって一文を付け加えただけなのにarticles関連のルーティングがたくさん増えてる。
なるほどー? さっきはwelcomeコントローラにindexっていうアクションを付け加えてnewして、そのタイミングでwelcome_indexっていうルーティングの設定がされたけど、逆にroutes.rbにリソースの設定をしてあげると、よくつかうアクション(CRUD)を自動でルーティングしてくれるってことか。
でもルーティングの設定がされただけで実態(コントローラやビュー)は何にもないよな。
これから作るってことなのかな。
5.1.土台を設置する
まずは新規記事を作成するページを作ろうとのこと。
さっきのルーティングの表のなかでその役目を果たしてくれそうなのは、articles/newだろう。
そのページを開いてみようとすると↓みたいな画面になる(rails serverは立ち上げておいてね)
(http://localhost:3000/articles/new)
この赤い感じの画面はRailsガイド上初めて出てきたけど、Railsのエラー画面だ。
なにかしらコードに問題があるとこの赤い画面になる。
そしてRouting Errorって言ってるね。
ルーティング表にかいてるURI Patternどおりに打ったはずだからさっきのURL(http://localhost:3000/articles/new) が間違っているわけじゃないだろう。
やっぱり、コントローラもビューもないからエラーになってるんじゃ…
「uninitialized constant ArticlesController」とエラー画面に出ているので調べてみると、やっぱりコントローラが存在しないエラーみたいだ。
ふむふむ。
じゃあコントローラ(とビュー)を作ってあげれば解決するわけだな。
ということでArticlesコントローラくんをgenerateしよう!
$bin/rails generate controller Articles
なんかapp/controllersの下にarticles_controller.rbってファイルを作っちゃえばいいように感じるけど、こわいからgenerateコマンドで生成した方が良さそう。
↑の結果を見ても他にもいくつかのファイルをcreateしてるし。
できた!articles_controller.rb!
中身はからっぽ。
class ArticlesController < ApplicationController
end
welcomeコントローラくんを作った時はindexアクションを追加するようにしたからcontroller.rbファイルには作成時からindexメソッドがあったけど、今回は特に何もアクションを追加してないので空っぽだ。
このファイルからわかることは、ArticlesControllerというクラスはApplicationControllerというクラスを継承していること。
そういえば、app/controllerの下にそんな名前の奴がいたなあ。
継承についてはあんまり詳しく書いてないけど、とりあえずコントローラはApplicationControllerが雛形となって作られるよってことを覚えておけばいいかな。
もう一回(http://localhost:3000/articles/new) にアクセスしてみよう。
今度はまた違うエラーが出た。
Unknown actionだって。なんとなく想像がつくぞ。
articlesコントローラくんにnewアクションなんてものはないぞ!って言っているのかな?
ていうか下にガッツリ書いてたorz
英語苦手orz
じゃあnewアクションをarticlesコントローラくんに実装してあげましょうか。
class ArticlesController < ApplicationController
def new
end
end
def new ~ endってかくことでarticlesコントローラくんにnewアクションを実装できる。
これはRubyのメソッドの追加の仕方だね。
(welcomeコントローラくんのindexアクションもこんな書き方してたね)
もういっかい!(http://localhost:3000/articles/new)
またエラーかよorz
ぜんぜんわからん!
でもまだやってないことがあるよな。
そう! ビューを作ってない!
Hello,Rails!を表示させる時だって、index.html.erbっていうビューを作ったよね。
ビュー作ってみるか。
場所はきっとここだ。
app/views/articles
(こんなフォルダいつ作ったっけ?)
ファイル名はきっとこれだ。
new.html.erb
(ビューの名前はアクション名と一緒だと学んだ)
中身は適当にこうしとこう。
<h1>New Article<h1>
よし!今度こそ!
(http://localhost:3000/articles/new)
きたー!
やっとだorz
5.2.最初のフォーム
New Articleって言われてもそんなページを作りたいんじゃなくて、作ろうとしているのは記事を投稿するページ!
(これじゃあHello,Rails!を表示させたのとおんなじじゃないか)
記事を投稿するためにはフォームが必要だ。
フォームといったらこんな感じ。
(記事投稿フォームを作ろうとしてわかる、このQiitaの編集フォームの洗練されていること…)
こんな画面を作るのはビューをいじればできそうだ。
でもいくつか疑問が思い浮かぶ。
投稿した記事はどこに保存されるの?
投稿した後どんな画面に遷移すればいいの?
保存した記事を読むためにはどうすればいいの?
まあ、読み進めてみよう。中身はよくわかんなくても、見た目をそれっぽく作ればとっかかりになるかもしれない。
Railsでフォームを作成するにはビューヘルパーなるものを使用するらしい。
ビューヘルパーには色々あって、フォームを作ったり、プルダウンリストを作ったり、リンクを作ったり、ボタンを作ったり、webサイトに必要な部品を簡単に書けるようにしてあるそうだ。
今回はフォームを作りたいのでform_withというヘルパーメソッドを使うみたい。
こういうのは必要な時に調べてコピペすればいいかな。(構文覚えるのなんてやってらんない。僕は初心者なので)
new.html.erbを以下のように書き換えればフォームができるって。
<h1>New Article</h1>
<%= form_with scope: :article, local: true do |form| %>
<p>
<%= form.label :title %><br>
<%= form.text_field :title %>
</p>
<p>
<%= form.label :text %><br>
<%= form.text_area :text %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
大事なことがいっぱい書いてある気がするぞー
とりあえず画面を表示してみよう(http://localhost:3000/articles/new)
わーお! 考えていた通りの(ちょっとしょぼめの)フォームができたぞ。
一行づつ確認してみよう。
<%= form_with scope: :article, local: true do |form| %>
<% end %>
これに囲まれている中にフォームで送信したい内容(今回はTitle,Text)を詰め込んでいく感じだ。
<%= ほにゃらら %>というのはhtmlの中にRubyの文を書く際の決まりらしい。
ビューのファイル名は〜html.erbってなってるけど、erbはembedded Ruby(組み込みRuby)という意味で、まさにhtmlの中にRubyのスクリプトを組み込んでいるよね。
つまり<% %>で囲まれている場所はRuby、そうでない場所はhtmlというわけだ。
そんでRubyで書ける場所にRailsに備わっているフォームヘルパーメソッドを書き込んでいるというわけ。
まずform_withって何者だっていうのを説明したかったんだけど、Rails 5.1からの新機能みたい。
巷にはRailsのフォームというとform_forやform_tagとか出てくるけど、天下のRailsガイド様はこんなことをおっしゃっている。
https://railsguides.jp/5_1_release_notes.html
「Rails 5.1より前のHTMLフォーム生成メソッドは、モデルインスタンス用のform_forと、カスタムURL用のform_tagの2種類がありました。
Rails 5.1ではこの2つのインターフェイスをform_withに統合し、URLベース、スコープ、モデルを指定してformタグを生成できるようになりました。」
えー! 統合しちゃったの!?
(ちょっとショック。でも確かに使い分けるのめんどくさかったよな)
ということで古い情報に惑わされずに、form_withを使おう! (Rails4以下で開発するなら話は別)
form_withの後ろにいくつかoptionがある。
ちょっくらRailsのAPIガイド(英語)をみてみるか…(英語を恐れるなかれ)
https://api.rubyonrails.org/v5.1/classes/ActionView/Helpers/FormHelper.html#method-i-form_with
今回使われているoptionだけ抜粋してみると
「:scope - The scope to prefix input field names with and thereby how the submitted parameters are grouped in controllers.」
「:local - By default form submits are remote and unobstrusive XHRs. Disable remote submits with local: true.」
…
…いみわからん
一旦諦めよう…ガイド様に従おう…
今の状態で画面にあるSave Articleボタンを押すとこんなエラーが出る
No route matches [POST] "/articles/new"
意味をそのまま訳すと、POSTの"/articles/new"っていうルートはないよっていっている。
そして下に現在のルーティングがこれ見よがしに載っている。
以前も確認したが以下のコマンドで現在のルーティング設定が確認できる。
bin/rails routes
URI Patternに"/articles/new"があるが、VerbはGETだ。POSTはない。
そもそもなんでSave ArticleボタンはPOSTリクエストを"/articles/new"に投げてるんだ?
疑問が山のようだ。
ガイドを読んでいくとソースに問題があるから直してって言われた。
なぜ…
<h1>New Article</h1>
<%= form_with scope: :article, url: articles_path , local: true do |form| %>
<p>
<%= form.label :title %><br>
<%= form.text_field :title %>
</p>
<p>
<%= form.label :text %><br>
<%= form.text_area :text %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
url: articles_path
ってoptionをつけくわえただけ。
これでSave Articleボタンを押すと
知ってるエラーになった。
Articleコントローラにはcreateというアクションはないよって。
やばい。フォームのとこでつまづきそうorz
絵にするとこんな感じだろうか
①フォームを作るにはform_withメソッドを使う
newビューくんにはform_withで作ったフォームが搭載されています。
form_withにはoptionでmethodというものが指定でき、POSTとかGETとか種類を選べるけど、今回は何にも指定していないので、デフォルトのPOSTになったようだ。
またフォームに入れた内容を送りたい相手も指定できる。それがurlオプションで、今回はarticles_pathを指定した。
ルーティングの設定表を見ると、Prefixがarticles(_path)でVerbがPOSTなのはarticles#createアクションである
※Prefixは空欄だがひとつ上のarticles GETと同じらしい。なんて紛らわしいんだ…
※Prefix + _pathという形式で利用できる。
つまりSave Articleボタンは「フォームの内容を、POSTで"/articles/create"アクションに送るよ」という機能を持っていたのだ! びっくり!
これで色々と納得がいくぞ!
最後に出たUnknown actionというエラーは、createアクションにフォームの内容を送ろうとして出たエラーだ。あたりまえじゃん。articleコントローラにそんなアクションまだ追加してないもん。
その一つ前、urlを指定する前に出たNo route matches ~というエラーは、createアクションに送ると明示しなかったのでデフォルトで自分(new)アクションに送ろうとしたため、そのPOSTリクエストに対応するルートがなかったからエラーになったんだ。
②フォームの送り先はルーティングの設定を確認する
今回ガイドに従ってPOSTのcreateアクションを指定したけど、そもそもこのルーティング設定って、routes.rbに追加したresources :articlesという一文のおかげでできたものだ。
ふーむ。
ルーティングって大事。
道はできた。あとはその道の先に街を作るだけだ。
その3
https://qiita.com/Natsuki_on_Rails/items/13416d8beacd3d7be1b3
参考
Railsガイド
https://railsguides.jp/
APIドキュメント
https://api.rubyonrails.org/v5.1/classes/ActionView/Helpers/FormHelper.html#method-i-form_with