その4から続きます。
21:リファクタリング
app/views/questions/new.html.erbとapp/views/questions/edit.html.erb
の大部分が同じ記述なのでDry原則を破っている
ではどうするか?共通化します。
app/questionsに新規ファイル
_form.html.erbを作成してカットペースト↓
※共通化して呼び出すファイルには_をつけるのがルール
<%= 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 %>
app/views/questions/new.html.erbを↓のように編集します。
<div>
  <div class="col-md-4 offset-md-4">
<!--中央に寄せる設定-->
    <h2 class="text-center">New question</h2>
   <%= render 'form' %>
  </div>
 </div>
app/views/questions/_form.html.erb以下の記述にします。
<form action="/questions" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓" /><input type="hidden" name="authenticity_token" value="aAhSPGiLYkFNeq6FyqkvGFyLFpLooxLsNyIdR4+/e+zq8FgqYyMlmNlWgruyu34AHg22g315u/gbC3GMDw63bw==" />
  <div class="form-group">
    <label>Name</label>
<!--テキストフィールドをつける-->
    <input class="form-control" type="text" name="question[name]" id="question_name" />
  </div>
<!--テキストフィールドをつける-->
  <div class="form-group">
    <label>Title</label>
     <input class="form-control" type="text" name="question[title]" id="question_title" />
  </div>
<!--テキストフィールドをつける-->
  <div class="form-group">
    <label>Content</label>
     <textarea class="form-control" name="question[content]" id="question_content">
     </textarea>
  </div>
<!--saveボタンを付ける-->
  <div class="text-center">
    <input type="submit" name="commit" value="Save" class="btn btn-primary" data-disable-with="Save" />
  </div>
</form>
同様にapp/views/questions/edit.html.erbも行います。
<div> <div class="col-md-4 offset-md-4"> <!--中央に寄せる設定--> <h2 class="text-center">Edit question</h2> <%= render 'form' %> </div> </div>
22:質問削除機能の追加
rails routesで確認すると↓
DELETE /questions/:id(.:format) questions#destroy
app/controllers/questions_controller.rbにて↓のように記述します。
def destroy @question = Question.find(params[:id]) @question.destroy redirect_to root_path, notice: 'Success!' end
デストロイアクションが呼ばれるとき、クエスチョンのIDが渡されるので、そのIDを使ってデーターベースから削除したいデータを取得し@questionに代入、
destroyメソッドを呼ぶことで削除して
ルートURLにとばしSuccess!を表示
app/views/questions/index.html.erbを
↓のように記述editの下の部分
[ <%= link_to 'Delete', question_path(question),
method: :delete, data:{ confirm: 'Are you sure?'} %> ]</td>
question_path(question)なのはルーティングから
(question)は引数を渡す(id)method: :delete,で削除
data:{ confirm: ‘Are you sure?’}で確認画面を作る
23:質問詳細画面へのリンク
app/views/questions/index.html.erbのtitle.idを↓のように記述します。
<%= link_to question.title, question_path(question) %> #↓idを渡す必要があるため↑questionのインスタンスを渡している question GET /questions/:id(.:format) questions#show
質問詳細画面へリンクしていればOKです。
24:回答投稿機能の概要
ユーザーが質問に対して、回答を投稿できる。
ユーザーが回答一覧を閲覧できる。
ユーザーが回答を編集できる。
ユーザーが回答を削除できる。
25:質問詳細画面の実装
app/controllers/questions_controller.rb↓を追加します。
def show @question = Question.find(params[:id]) end
app/views/questions/show.html.erbにて↓を記述します。
#rowはコンテナを水平に分割し上から下へと並べます。
<div class="row">
#rowの中にcolを定義しレイアウトを組みます
#画面幅Mediumのグリッド個数12という意味です。
  <div class="col-md-12">
    <h2><%= @question.title %></h2>
  </div>
    Content: <%= @question.content %>
   </div>
  <div>
    Name: <%= @question.name %>
  </div>
<hr>
  <div>
   <%= link_to '> home', root_path %>
  </div>
 </div>
</div>

質問詳細画面が表示されていればOKです。
26:Answersコントローラーを作成します。
rails g controller answers edit
保有するアクションはそのまま編集する画面で使用するedit
↓のようにファイルが自動生成される
create app/controllers/answers_controller.rb route get 'answers/edit' invoke erb create app/views/answers create app/views/answers/edit.html.erb invoke test_unit create test/controllers/answers_controller_test.rb invoke helper create app/helpers/answers_helper.rb invoke test_unit invoke assets invoke coffee create app/assets/javascripts/answers.coffee invoke scss create app/assets/stylesheets/answers.scss
重要なのはapp/controllers/answers_controller.rb
app/views/answers/edit.html.erbあとはルーティングなどです。
27:Answerモデルの作成
テーブルの構造 一対多の関係で作ります。
ひとつの質問に対して複数の回答を表示するため、テーブルの構造が一対多になります。
rails g model answer question:references name:string content:text
モデルの名前が単数であることに注意して、
question:references1対多の定義をしています。
生成されたもの↓
invoke active_record create db/migrate/20210304022906_create_answers.rb create app/models/answer.rb invoke test_unit create test/models/answer_test.rb create test/fixtures/answers.yml
db/migrate/20210320022906_create_answers.rbは
class CreateAnswers < ActiveRecord::Migration[5.2]
  def change
    create_table :answers do |t|
    t.references :question, foreign_key: true
    t.string :name
    t.text :content
    t.timestamps
    end
  end
end
answersテーブルを作成するための定義がRubyでされている
app/models/answer.rbには
class Answer < ApplicationRecord belongs_to :question end #Answerはquestion↑に紐づく(belong_to)という意味 #answer(答え)から見てquestion(質問)は一つあるという意味
app/models/question.rbに↓記述を追加します。
class Question < ApplicationRecord has_many :answers, dependent: :destroy #←追加 ~~~~~~~~~~~~~以下略 end
questionは複数のanswersを持っているという意味です。
(Yahoo知恵袋のように質問に対して複数の人が質問に答えてくれるから)
dependent: :destroyは親である質問が削除されたら複数の回答も
みんな削除するよという意味です。
変更をデータベースに反映します。
rails db:migrate
エラーが発生しなければOK
28:回答機能関連のルーティング
app/config/routes.rbにて↓のように記述
root 'questions#index' resources :questions do resources :answers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~以下略 end
rails routes ↓のようにanswers関連のルーティングが増えているのを確認します。 answers#index POST /questions/:question_id/answers(.:format) answers#create new_question_answer GET /questions/:question_id/answers/new(.:format) answers#new edit_question_answer GET /questions/:question_id/answers/:id/edit(.:format) answers#edit question_answer GET /questions/:question_id/answers/:id(.:format) answers#show PATCH /questions/:question_id/answers/:id(.:format) answers#update PUT /questions/:question_id/answers/:id(.:format) answers#update DELETE /questions/:question_id/answers/:id(.:format) answers#destroy
29:回答投稿機能
app/controllers/questions_controller.rb↓のように記述します。
def show @question = Question.find(params[:id]) @answer = Answer.new end
空のインスタンスを作成してインスタンス変数@answerに代入してviewで使えるようにします。
30:回答投稿機能のviewを作成
app/views/answers/show.html.erbで記述します(<hr>タグから)
<hr>
<h3>Post new answer.</h3>
  <%= form_with model: [@question, @answer], local: true do |f| %>
    <%= f.hidden_field :question_id, { value: @question.id} %>
      <div class="form-group">
        <label>Name</label>
      <%=f.text_field :name, class: 'form-control' %>
      </div>
    <div class="form-group">
      <label>Content</label>
        <%= f.text_area :content, class: 'form-control' %>
    </div>
   <div class="text-center">
     <%= f.submit "Post", class: 'btn btn-primary' %>
   </div>
<% end %>
[@question, @answer]questionモデルに紐づくanswerモデルを
フォームで送信したい時は、
form_withのmodelに配列で@questionと@answerのインスタンスを渡します。
<%= f.hidden_field :question_id, { value: @question.id} %>
↑htmlには表示されているけど↑ページに描画されない値としてセットしています。
2つのインスタンスの値はcontrollerのshowの部分で渡しています。
def show @question = Question.find(params[:id]) @answer = Answer.new end
このようなビューが作成されてるのを確認したらOKです。

次にPostが押されたときの処理を実装します。

