11:新規質問機能の投稿View
app/views/questions/new.html.erbを↓のように記述
<div class="col-md-4 offset-md-4"> <!--中央に寄せる設定--> <h2 class="text-center">New question</h2> <%= form_with model: @question, local: true do |f| %> <div class="form-group"> <label>Name</label> <!--テキストフィールドをつける--> <%= f.text_field :name, class: "form-control" %> </div> <!--テキストフィールドをつける--> <div class="form-group"> <label>Title</label> <%= f.text_field :title, class: "form-control" %> </div> <!--テキストフィールドをつける--> <div class="form-group"> <label>Content</label> <%= f.text_field :Content, class: "form-control" %> </div> <!--saveボタンを付ける--> <div class="text-center"> <%= f.submit "Save", class: "btn btn-primary" %> </div> <% end %> </div>
form_with,text_field,submitなどのメソッドはフォームヘルパーと呼ばれフォームに関するhtmlを自動的に生成してくれます。
form_with,はrails5.1になってからでてform_forなどは非推奨になったので移行しましょう。
model: @question
コントローラから渡されたクエスチョンモデルのモデルオブジェクトを設定
local: true 非同期通信を使ったフォームを無効にしている
次に動作確認をしたいのでコントローラからビューに
Questionモデルのインスタンスを渡す機能の実装
app/controllers/questions_controller.rbに↓のように記述
def new @question = Question.new end
Questionモデルの新規インスタンスを生成して@questionに代入して
app/views/questions/new.html.erbに渡してform_withで利用しています。
form_withタグによって↓生成された
<form action=”/questions” accept-charset=”UTF-8″ method=”post”>
慣れるまではフォームヘルパーによってどんなHTMLタグができるか確認しましょう!
12:投稿データの保存
rails routesから
POST /questions(.:format) questions#create
この設定になるのでapp/controllers/questions_controller.rbに↓のように記述します。
class QuestionsController < ApplicationController def index #questionsテーブルからすべての質問を取得する @questions = Question.all end def show end def new @question = Question.new end def create @question = Question.new(question_params) if @question.save redirect_to root_path, notice: 'success!' else flash[:alert] = 'Save error!' end end def edit end private def question_params params.require(:question).permit(:name, :title, :content) end end
投稿データを保存 def create @question = Question.new(question_params) #フォームからデータを受け取ってデータベースに値を保存する if @question.save #セーブが成功した時にルートURLに飛びsuccess!を表示 redirect_to root_path, notice: 'success!' #セーブ失敗したとき flash[:alert] = 'Save error!' end end
セーブして新規投稿できたらOKです。
Contentの部分が入力しづらいので拡大する
app/views/questions/new.html.erbを↓のように変更
↓ココ
<%= f.text_area :Content, class: “form-control” %>
テキストフィールドが広くなったのを確認します。
13:ストロングパラメーター
投稿データの保存とフォームにデータを入力してセーブボタンを押すとフォームからデータがPostで送信されて、Questions_controllerのcreateアクションが呼ばれる
次にこの部分で↓Questionインスタンスを生成して@questionに代入
def create @question = Question.new(question_params) #↑question_paramsメソッドの戻り値を利用している if @question.save redirect_to root_path, notice: 'success!' else flash[:alert] = 'Save error!' render :new #←newへ飛ばす end end def edit end private def question_params params.require(:question).permit(:name, :title, :content) end end
ストロングパラメーターという仕組みを使って
フォームから送られてきた特定のデータのみ受け付けます。
フォームから送信されたデータは信頼できないので、question_paramsメソッドを使って
指定したデータだけを登録対象にしています。
paramsメソッドにはフォームから送られてきたデータが入り、
params.require(:question).permit(:name, :title, :content)
↑フォームから送られてきたquestionのデータの内のname, title, contentだけ使うようにします。
フォームからIdの値が送られてきても無視する
フォームから送信されたデータは信用できない(書き換えられて致命的な脆弱性になるなど)
例:更新対象のカラムを指定しないとポイント残高を書き換えられるなど
指定したカラムを戻り値として渡して、更新用のデータとします。(@question)
セーブが成功して(true)になったらルートURLに飛ばしメッセージ(Success!)の値を渡します。
14:paramsに入るデータをデバッグツールbyebugで確認
Gemfileにて↓ group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] end
開発環境とテストで、Gemを読み込むことになっています。
本番環境では読み込まないです。
app/controllers/questions_controller.rbにて↓
private def question_params byebug #←プログラムが実行したときココに来るとプログラムの実行が止まる params.require(:question).permit(:name, :title, :content) end end
questions/newにて適当な値を入れます。 Name a Title b Content c save ターミナルに↓のようなものが表示されています。 20: end 21: def edit 22: end 23: 24: private 25: def question_params 26: byebug => 27: params.require(:question).permit(:name, :title, :content) 28: end 29: end paramsとコマンドすると↓ (byebug) params <ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=> "5xd2GRDEUu4AasvoycOs7LON1kRoMpgrf1INGxZT9yw==", "question"=>{"name"=>"a", "title"=>"b", "Content"=>"c"}, "commit"=>"Save", "controller"=>"questions", "action"=>"create"} permitted: false> フォームから送られてきたデータ↑ authenticity_tokenフォームデータの改ざん防止のためのトークン "question"=>{"name"=>"a", "title"=>"b","Content"=>"c"}, ↑ここがさっき入力したものになります。
quitでbyebugを終了できます。byebugの記述も消しておきます。
検証で見たとき↓authenticity_tokenが隠されているのがわかります
<input type=”hidden” name=”authenticity_token”
value=”5xd2GRDEUu4Aasvoa8GzGBKfwiRks1F8f30uKLnClfTVWFJQAytdQwduG4nycOs7LON1kRoMpgrf1INGxZT9yw==”>
15:バリデートの追加を開発
値が空でも送れてしまうので、咎めておきたいときに
app/models/question.rbにて↓を記述
class Question < ApplicationRecord validates :name, presence: true validates :title, presence: true validates :content, presence: true end
16:エラーメッセージの表示を開発
成功したのか失敗したのかわかりやすくするためにメッセージを表示したいときに
app/views/application.html.erbにて追加↓
<body> <div class="container"> <% if flash[:notice] %> <p class="text-success"><%= flash[:notice] %></p> <% end %> <% if flash[:notice] %> <p class="text-danger"><%= flash[:alert] %></p> <% end %> <%= yield %>
フォームを空にした時に、Saveした時Save error!が表示されたらOKです!
バリデーションの確認を両方する形になります。
17:質問投稿画面へのリンクを開発
app/views/questions/index.html.erb以下の記述を追加します。
</table>の下に <div> <%= link_to 'New question', new_question_path%> </div> # 第一引数↑ 第2引数↑rootに設定すれば当然ルートURLにいく link_toはビューヘルパーと呼ばれハイパーリンクを生成するためのメソッド <a>タグを生成するメソッドNew questionはroutes.rbを見ればわかリます。
18:質問編集画面のリンクを開発
app/views/questions/index.html.erb のeditの部分から <td>[ <%= link_to 'edit', edit_question_path(question) %> ] [Delete]</td> </tr>
19:質問編集画面を開発
app/views/questions/new.html.erbを流用します。(ほぼ変わらないため)
app/views/questions/edit.html.erbで↓のように記述します。
<div> <div class="col-md-4 offset-md-4"> <!--中央に寄せる設定--> <h2 class="text-center">Edit question</h2> <%= form_with model: @question, local: true do |f| %> <div class="form-group"> <label>Name</label> <!--テキストフィールドをつける--> <%= f.text_field :name, class: "form-control" %> </div> <!--テキストフィールドをつける--> <div class="form-group"> <label>Title</label> <%= f.text_field :title, class: "form-control" %> </div> <!--テキストフィールドをつける--> <div class="form-group"> <label>Content</label> <%= f.text_area :content, class: "form-control" %> </div> <!--saveボタンを付ける--> <div class="text-center"> <%= f.submit "Save", class: "btn btn-primary" %> </div> <% end %> </div>
20:質問編集画面を開発
app/controllers/questions_controller.rbを編集def editの部分
def edit @question = Question.find(params[:id]) end #URLにquestions/1/editのようにidが入るため↑がいる #paramsとはRailsで送られてきた値を受け取るためのメソッド #findは、modelの検索機能の1つです。
更にsave機能の実装のため編集
class QuestionsController < ApplicationController def index #questionsテーブルからすべての質問を取得する @questions = Question.all end def show end def new @question = Question.new end def create @question = Question.new(question_params) if @question.save redirect_to root_path, notice: 'success!' else flash[:alert] = 'Save error!' render :new end end def edit @question = Question.find(params[:id]) end def update #idをもとにDBからデータを取得↓ @question = Question.find(params[:id]) if @question.update(question_params) redirect_to root_path, notice: 'Success!' else flash[:alert] = 'Save error!' render :edit end end private def question_params params.require(:question).permit(:name, :title, :content) end end
更新フォームから送信されたデータは信用できないので、
question_paramsつまりストロングパラメーターを経由して値を利用します。
保存が成功したらifが成立するのでルートURLへ飛びSuccess!表示
失敗したらeditのままでSave error!を表示します。
編集画面へのリンクから↓のように値がSETされていて新しく値を設定して、更新できたらOKです。