railsのまとめ4(ミニQ&Aサイトを作るその2)

その3から続きます

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です。

その5に続きます

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です