「DIVE INTO CODE」学習記録 #28
こんにちは。
28日目。controllerにアクションを追加する。「member」と「collection」の違い。
学習内容
【オリジナルアプリ開発「免許学科試験学習アプリ」】
- コントローラーのアクション追加実践
- ルーティングの確認
- トップページデザインを考える
感想
今回は免許アプリの問題一覧を修正して行きます。
前回の日記(【Rails】csvファイルをDBに読み込ませる【DIVE INTO CODE】)にて、
DBに無事問題を読み込ませることに成功したので、
今度はこのDBに格納された問題データをviewまで繋げることにします。
まず、表示の仕方を考える。
現状、僕の作成している免許アプリの問題一覧画面は、
「questions」という名前のコントローラーで管理しており、
最初からついているindexとshowアクションのみです。
したがって、viewへの表示は、
「 問題一覧(index)=> 問題詳細(show)」
しかできない状況です。
色々調べてみましたが、
免許アプリに実装する総問題数は1200問ぐらいを想定しています。
これを一覧として全て同じ画面に表示するのは、
言うまでもなく「おかしい」です。
また、免許の問題には仮免と本試験ともに、
「分野」が存在します。
とりあえず「分野別問題一覧画面」は必須である。
なのでなんとかして「分野別問題一覧画面」を表示できるルーティングを作りたい。
では、ルーティングを増やすにはどうしたらいいのか。
今の僕が知ってる知識では、
- 新しいコントローラーを増やす。
- 既存コントローラーにアクションを増やす。
の2つです。
(deviseなどgemをインストールして、よくわからないけど生成されてるルーティングは除く。)
コントローラー増やして作るのは今まで何回もやってるので、
今回は「既存コントローラーにアクションを増やす」をやってみよう。
つまり、今回やることはアクション追加して、
「 問題一覧(index)=> 問題詳細(show)」
これを、
「 問題分野一覧(index)=> 分野別問題一覧(devide) => 問題詳細(show)」
にします。
追加アクションは「devide」とします。
では、実際にやってみます。
「member」メソッドを使ったルーティング追加
まず、アクションについて。
Railsのコントローラーにはデフォルトで、7つのアクションがあります。
「index、new、create、show、edit、update、destroy」の7つ。
それぞれ、単語の意味どおりの機能を持っています。
Railsというフレームワーク内では、controller内にあるこれらのアクションが、
viewとmodelに対し色々指示を出すことでアプリの基本機能を実装できる仕組みです。
「このコントローラーのアクションに8つ目を追加したい。」
こんな悩みをお持ちの方はいらっしゃいませんか?
そんな時にはこちらの「member」メソッドもしくは「collection」メソッドがオススメです。
1、ルーティングの追加(アクション追加メソッド「member」と「collection」)
アクション追加メソッドは「member」と「collection」があります。
今回は「member」を使うのですが、
どちらも基本的に使い方は一緒です。
railsaアプリのconfigディレクトリ内にあるroutes.rbファイルに以下のようにコーディングします。
config/routes.rb
Rails.application.routes.draw do resources :questions do member do get :devide end end end
今回書いたのがこれです。
もともと書いてあった「resources :questions」に、
「member do〜」を噛ませています。
config/routes.rb
Rails.application.routes.draw do resources :questions do collection do post :confirm end end end
こっちは前にDICカリキュラムで、ブログ投稿前のcomfirm画面を作成したときのものです。
こちらは「form」でユーザーが書いたブログ内容のパラメータが乗っかっているので「get」ではなく「post」。
「member」と「collection」の違い
「member」と「collection」。二つあるからには違いがあるわけで、
今回「member」を採用したもの「collection」では無理だったからで。
何が違うのか。
それは、「id」を持ったルーティングにするか、しないか。
パラメータで「id」を持たせて、アクションに引き渡したいか、
それとも「id」を引き渡す必要がないかで使い分けることができます。
「member」
・・・「id」がついたルーティングになる。パスが「localhost3000/questions/1/devide」のようになる。
「collection」
・・・「id」がつかないルーティングになる。パスが「localhost3000/questions/devide」のようになる。
ターミナルで「$rails routes」してルーティング確認すれば違いがわかります。検索すれば色々詳しく出てきます。
今回僕がしたかったのは、
「分野別問題一覧ページ」の作成。
例えば、ユーザーが「分野一覧」画面から、”運転の心得”という分野を選択したとします。
viewには「どの分野のユーザーが選択したか」をcontrollerに伝えてもらわなければなりません。
どれ選択したかを知っているのは、実際にお客さまと対面している「view」しか知らないわけですから。
viewからcontrollerへ、”運転の心得”の「id」をそのまま持たせて、次の「devide」アクションに繋げる。
問題ごとに何かしらの「分野id」を持っているので、同じ「分野id」を持った問題ごとに分けて一覧を表示できる。
ていう理由で「member」を使いました。
2、アクションの追加
コントローラーにアクションを追加します。
「devide」アクションのみ抜粋しております。
app/contollers/questions_controller.rb
class QuestionsController < ApplicationController def devide @devide_questions = Question.where(field_id: params[:id]) end end
「field_id」が分野idです。
パラメーターで送られてきたidを条件にして、
「Question」モデルから、一致したidを持っている問題を全てを
「@devide_questions」というインスタンス変数に格納してます。
3、ビューの追加
「devide」アクションが起動した際に表示するviewを作成します。
app/views/questions/devide.html.erb
<h1><%= @devide_questions.first.field.field_name %></h1> <% @devide_questions.each do |question| %> <ul> <li>問題:<%= question.content %></li> <li>正誤:<%= question.answer %></li> <li>解説:<%= question.explanation %></li> </ul> <span><%= link_to '<この問題を詳しく>', question %></span> <br> <% end %> <span><%= link_to '<分野一覧へ戻る>', questions_path %></span>
<%= @devide_questions.first.field.field_name %>は、
分野名を見出しにしたかったのですが、まとめてeachに入れると
繰り返し回数分見出しができてしまったので、外に出しました。
見出しは1しか必要ありません。
questionモデルとfieldモデルは「field_id」を外部キーとしてアソシエーションしてます。
これで完了です。
4、実際の画面
実際の画面が以下です。
トップから紹介していきます。
デザインは試作段階なので多めにみてください。
ノートの背景画像に付箋のボタン。
勉強ノート風にとりあえず見立ててます。
ここのcssは全て「サルカワ 」というcssの見本がコピペで使えるサイトから引っ張ってきたものです。
ハンバーガーメニューを押すと、
安定のbootstrapから引用。
今の所オリジナリティはありません。
「学科試験 分野一覧」を押すと、
DBから引っ張ってきた分野データがちゃんと表示されます。
「運転者の心得」を押すと、
”運転者の心得”の「field_id」を持った問題だけ表示されます。
※分野と問題をちゃんと対応させてないため、上に出ている問題は”運転者の心得”の本当の問題ではありません。
まあ現状こんな感じです。
ちなみに作成途中の一問一答。
まだまだ完成してませんが、今の所こんな感じです。
「○」か「×」を押すと、
答えがJSで表示されます。
JSは理解が不十分すぎて途方にくれてます。
今回はこのくらいで。
以上ありがとうございました。