🗂

Ruby on Rails 機能の追加

2023/02/18に公開

一覧画面のコントローラーを開発しよう

タスク一覧ページがリクエストされた時に呼ばれる
タスクスコントローラーのindexメソッドを実装!!

ファイルエクスプローラーで
app→controllers→task_controller.rb
ファイルを開く

ルーティングでいうと、

1行目のtasks#indexの行を実装していく!

次のように入力する

def index
  @tasks = Task.all
end

Task.allでタスクステーブルから全てのレコードを取得!
(開発者がデータベースを操作するためのSQLを書かなくて済む!)
実際にはrailsが裏でSQLを発行している。

SQLはターミナルに表示されるので、
意図しないSQLが発行されていないか確認できる!

Task.allの戻り値を@tasksに代入

@tasksはタスクの一覧を格納するために使うインスタンス変数
(このインスタンス変数はview側でも利用できる)

一覧画面のビューを開発しよう

先ほど作成したTasksControllerの
indexメソッドに対応するビューを開発する
(タスクの一覧表示画面のビューを作成)

app→views→tasksファイル配下に
index.html.erbファイルを作る

次のように入力する

<h1>Tasks</h1
<ul>
  <% @tasks.each do |task| %>
    <li>
      <%= check_box_tag '','' %>
      <%= task.title %>
    </li>
  <% end %>
</ul>

補足
このファイルはerbテンプレートrubyのプログラムが埋め込める
テンプレートを使っている

ファイルのベースはhtmlだが、テンプレートエンジンerbを使うことにより、
<% %>
<%= %>
で囲まれた部分にはrubyのプログラムを書くことができる

コントローラーから渡されたインスタンス変数@tasksには、
複数のタスクのデータが入っているので
それをrubyのeachで一つずつ取り出しながら、
タスクの完了状態を管理するためのcheck_box_tag(ダミー)と
タスクのタイトルを出力している

⚠️よくある間違い!⚠️
<% %>
イコール記号がないものは任意のコードを実行したい時に使う
<%= %>
イコール記号があるものは、何かページに出力したい時に使う

railsサーバーを起動し、動作確認をする!

このようにデータベースに登録した
タスク名とチェックボックスがリスト表示されていればOK

新規タスクの追加機能を開発しよう

ルーティングのtasks#newの行を使って実装していく

TasksControllerのnewメソッドを実装する
(タスクを新規に追加する画面の実装)

  def new 
    @task = Task.new
  end

タスクモデルのインスタンスをnewメソッドで作り、
インスタンス変数@taskに入れる

@taskはview側でフォームを作成する時に利用する

views配下のtasksの中にnew.html.erbファイルを作る!
次のように入力!

<h1>New</h1>
<%= form_with model: @task do |form| %>
<% end %>

form_withヘルパーメソッドでformビルダーをインスタンス化する
formビルダーと呼ばれるrailsの機能を使用してフォームを作成!

formビルダーを使用すると、最小限のコードを記述すれば
railsの規則に従ったフォームを簡単に出力できる!

form_withに利用するモデルのインスタンスをセットすると、
ファイルのPWなどを自動的に設定してくれた上で
HTMLのコードが生成される

ここでいうヘルパーメソッドとはviewをよりシンプルに書くために用意された機能

次のように、フォームの各パーツを実装することができる!

<p>
  <%= form.label :title %><br>
  <%= form.text_field :title %>
</p>
<p>
  <%= form.submit %>
</p>

URLに/tasks/new入力して、ページを表示すると、、

このように表示されていればOK!

Googleクロムのデベロッパーツールで
どのようなHTMLが生成されているか見てみる

例えば、Titleラベルを右クリックして検証すると、
formタグが生成されているのがわかる🙆🏻‍♀️

form_withのモデルにインスタンスを渡すことで
適切なPWであったり、メソッドが指定されている。

labelメソッドはラベルテキストを生成する。
text_fieldメソッドは、テキストボックスを生成する!
HTMLのタグとしては、input type="text"が生成されている。

submitメソッドはsubmitボタンを生成する!
HTMLのinput type="submit"タグを生成

次に、送信ボタンが押された時のコントローラーの処理

tasks#createの行を使う

tasks_controllerを開き
送信ボタンが押された時に呼ばれるcreateメソッドを実装していく!

createメソッドではフォームから送られてきたデータを元に
データベースに値を保存する

フォームから送信されるデータはpalamsというメソッドで所得できる!

palamsメソッドは、フォームなどによって
送られてきた情報(パラメーター)を取得するメソッド!

簡単にできる方法としてはpメソッドを使う!

  def create
    p params
  end

サーバーにデータを送信すると、
createメソッドが呼ばれて
pメソッドでparamsの値がターミナルに出力される

ターミナルにParametersの値が出力された状態であれば、
それを開発に利用することも可能!

ストロングパラメーターを利用しよう

ストロングパラメーター(Strong Parameters)とは、

Ruby on Railsでリクエストパラメータを安全に受け取るための仕組みのこと!
ストロングパラメーターは、Mass Assignment(一括代入)攻撃を防止するために導入された。

Mass Assignment攻撃とは、、

ユーザーが送信したパラメーターを直接モデルに保存することによって、
意図しないデータが保存されたり、不正な操作が行われることを意図した攻撃。
例えば、ユーザーがフォームから送信したパラメーターを直接モデルに保存した場合、
ユーザーが送信したはずのデータとは異なる、不正なデータが保存されることがある。

ストロングパラメーターを使用することで、
不正なデータの保存を防止し、セキュリティを向上させることができる。

private
  def task_params
    params.require(:task).permit(:title)
  end

privateを指定するとそれより配下は
privateメソッドとして扱われる
class内からのみ利用できる!

メソッド名は慣習として
モデル名_paramsとする

requireメソッドでデータのオブジェクト名を指定する
permitメソッドでデータベース保存の処理に使うカラムを指定
(カンマ区切りで複数指定できる!)

指定した以外のデータを送ってくる悪意のあるリクエストを受けた時に
permitメソッドで許可していない項目については
データベースの値の変更には使われなくなり、データの扱いがより安全になる🙆🏻‍♀️

データベースに値を保存しよう

  def create
    @task = Task.new(task_params)
    @task.save
    redirect_to root_path
  end

createボタンは新規登録ボタンが押された時に呼ばれる!

フォームに入力されたデータをもとにタスクモデルを作成。
task_params経由で、データをモデルにセットすることで
フォームから送信されたデータのうち、
タイトルカラムのみデータベースに保存するようにしている🙆🏻‍♀
セーブを行い、ルートパスにリダイレクトする。

データベースに新規タスクが追加されて
一覧画面に遷移、値が追加されていればOK!

新規追加画面へのリンクを設置しよう

一覧画面からタスクの新規追加画面へ遷移できるリンクを設置

index.html.erbファイルに次のように記述!

<%= link_to 'new', new_task_path %>

link_toメソッドとは、、ハイパーリンクを生成するヘルパー
'new'の部分がハイパーリンクを設定したい文字列
new_task_pathがパスになる
(Prefix、new_taskに_pathをつけたものを指定している)

動作検証をして、
newのリンクをクリックして新規追加画面へ遷移すればOK!

バリデーションを追加しよう

バリデーションとは?

  • 記述・入力したデータが、あらかじめ規定された条件た仕様、形式などに適合しているかどうかを検証・確認すること
  • 例)未入力チェック、文字数チェック

バリデーションの練習

  • Title...未入力チェック、5文字以上であること

この条件に引っ掛かる場合は、データをセーブできないようにする
さらに、バリデーションエラーのメッセージを表示して値を修正するように促す

app→models→task.rbファイルに記述

validates :title, presence: true, length: { minimum: 5}

これで、タイトルカラムについてpresence: trueで未入力チェック
length: { minimum: 5}の記述で5文字以上の文字列が入力されているかチェック!

次にtasks_controllerを修正!
createメソッドを編集する

  def create
    @task = Task.new(task_params)
    if @task.save
    redirect_to root_path
  else
    render 'new', status: :unprocessable_entity
  end
end

renderメソッドはviewファイルを指定して表示することができるメソッド
status: :unprocessable_entityでステータスコード422でレンダリングする。

422はバリデーションエラーの場合に返すステータスコード

次にnew.html.erbファイルを編集!
エラーメッセージを表示する部分を記述

text_fieldの下に記述

  <% if @task.errors.any? %>
    <%= @task.errors.messages[:title][0] %>
  <% end %>

バリデーションエラーがある場合は、
@task.errors.any?がtrueになるので
下のエラー表示部分を有効にする。
@task.errors.messagesに配列でエラー内容が入っているので
titleの先頭の1つについて画面に表示する。

動作確認
新規タスク登録画面を開き、
タイトルを空のまま送信すると
can't be blankと表示されてデータベースに値は保存されない

5文字以下を入力して送信しても
is too short(minimum is 5 characters)
短すぎて保存ができません。

5文字以上入力して送信すると、
データベースに値が保存されて一覧画面に遷移できた!

一覧画面から編集画面へのリンクを作成しよう

タスクの編集機能を開発していく!
一覧画面の各タスクに編集画面へのリンクをつける

編集ページの表示には、tasks#editの行のルーティングを使う!

index.html.erbを開き編集!
task.titleの下に次のように入力

<%= link_to '[edit]', edit_task_path(task) %>

ファイルを保存し、ページをリロードすると
編集画面へのリンクがついた!🙆🏻‍♀️

編集画面を開発しよう

編集画面を表示するときに使うルーティングはtasks#editの行
編集画面のフォームから送信されたデータを受け取って処理をすることに使う
ルーティングはtasks#updateの行

編集画面のviewを作成する
app→views→tasks配下にedit.html.erbファイルを作成

tasks_controllerを開き、createメソッドの下に書いていく!
editメソッドを作成

  def edit
    @task = Task.find(params[:id])
  end

編集するタスクの情報をデータベースから取得する必要がある。
編集画面を表示するときのURLに着目すると
/tasks/1/edit
とあるが、1のところはtasksのID!

このIDを使ってデータベースから該当のレコードを取得できる。
ターミナルを見ると、

Parameters: {"id"=>"1"}

と表示されている。つまりIDはparamsメソッドで取得できる!

paramsからidだけを抜き出すには、

p params[:id]

ターミナルを見るとIDが出力されている。

idを指定してタスクステーブルからレコードを取得するには、、

@task = Task.find(params[:id])

タスクモデルのfindメソッドで引数にidを指定することで、
該当のレコードを取得できる
インスタンス変数@taskに代入して、viewに渡す。

次に、edit.html.erbファイルを編集!
new.html.erbと見出しを除いて同じになるのでコピペして
NewをEditに変更!

既存の値もセットされて表示される!

次に送信ボタンを押した時の処理
tasks_controllerを開き、updateメソッドを使い記述する!

  def update
    @task = Task.find(params[:id])
    if @task.update(task_params)
      redirect_to root_path
    else
      render 'edit', status: :unprocessable_entity
    end
  end

まず、タスクのインスタンスをフォームから送られてきたデータを使って作成する。
該当のレコードをアップデートするには、モデルのupdateメソッドを利用。
ストロングパラメーターを利用し、updateが成功したら
root_pathへリダイレクトする。

もしバリデーションエラーなどでupdateが失敗した場合は、
elseの方でもう一度編集画面を表示する!

動作確認
Titleに5文字以上の文字を入力して、
タイトルが書き変わっていればOK!!

削除機能を開発しよう

タスクを削除する機能を開発
一覧ページの各タスクに削除リンクを設置する!

削除には、tasks#destroyの行のルーティングを利用

tasks_controllerを開き、updateメソッドの下にdestroyメソッドを記述!

def destroy
    @task = Task.find(params[:id])
    @task.destroy
    redirect_to root_path, status: :see_other
end

φ(・
まずデータベースから該当のidのタスクを取得して@taskに入れる!
destroyメソッドで該当のタスクを削除

削除が終わったら、root_pathへリダイレクト

redirect_toメソッドでstatus: :see_otherを指定すると
HTTPステータスコード303が使われる!

(意味は新規リソースへの移動)
フォームへ投稿後に、何らかのURLに転送したいときに使われるコード
ステータス:see_otherをつけないと、
意図しない不具合を発生させる原因になるので必ず記述する!

次に、index.html.erbファイルを開き
削除を実行するためのリンクを作成する!

編集リンクの下に記述していく!

<%= link_to '[destroy]', task_path(task)
data: { turbo_method: 'delete', turbo_confirm: 'Are you sure?'}%>

point
turboメソッドにdeleteを指定する。
確認ダイヤルを出すためにturbo_confirmの部分に、
ダイヤログに表示させるメッセージを書いている。

rails7では、turboというrailsの記述でJSのような
動作を簡易的に実現できる仕組みが使われているため
turbo_というprefixをつけるルールになっている!

ファイルを保存して、動作確認!

削除したいタスクのdestroyをクリックして、
確認ダイヤルのOKボタンを押すとデータが削除できた!🙆🏻‍♀️

リファクタリングをしよう

railsの基本理念に同じことを繰り返さない
Don't Repeat Yourselfというものがある。

コードの共通化を行う!
複数の場所に同じコードを繰り返し記述するのは避けましょうということ。

例えば、フォームの入力項目が増えた時に
一箇所変更を加えればよくなるためメンテナンス性が高まる!

機能は変えずにコードを整理してより良くすることを
リファクタリングという

viewsフォルダのtasksフォルダ配下に
_form.html.erbファイルを作成!

共通化して呼び出すビューのファイル名の先頭には_をつけるルール!

そこに共通化するコードを記述する!

_form.html.erbファイルを呼び出す記述

<%= render partial: 'form' %>

renderメソッドを指定して、partialにファイルを指定する!
(先頭の_や拡張子は書かないルール!)

partialとは、一部のや部分的なといった意味!

ファイルを保存して、動作確認!
同じように動作すればOK〜〜〜


明日で今やっている講座終わりそうだから、
アドバイスをもらった通りにまた最初から繰り返しやってみる!!
学校行くまでの予習期間、
今やっていることを自分のものにできるよう頑張る!

Discussion