Ruby on Rails

ビューとフォーム

ERBで画面を作り、入力値を安全に受け取ってエラーも利用者へ伝えます。

01

ERBでHTMLを作る

ERBはHTMLの中へRubyの値や繰り返しを埋め込むテンプレートです。表示する値には出力タグ、処理だけには処理タグを使います。

index.html.erbERB
<h1>記事一覧</h1>
<% @articles.each do |article| %>
  <article>
    <h2><%= link_to article.title, article_path(article) %></h2>
    <p><%= truncate(article.body, length: 80) %></p>
  </article>
<% end %>

link_toなどのヘルパーを使うと、URLの書き間違いを減らせます。表示用の加工はヘルパーやプレゼンテーション層へまとめ、複雑な処理をビューに増やさないようにします。

02

フォームを作る

_form.html.erbERB
<%= form_with model: article do |form| %>
  <div>
    <%= form.label :title, "タイトル" %>
    <%= form.text_field :title %>
  </div>
  <div>
    <%= form.label :body, "本文" %>
    <%= form.text_area :body, rows: 8 %>
  </div>
  <%= form.submit "保存" %>
<% end %>

新規作成と編集で同じ部分テンプレートを使えば、入力欄の変更を一か所で済ませられます。ファイル名の先頭のアンダースコアは部分テンプレートを表します。

03

入力エラーを表示する

エラー表示ERB
<% if article.errors.any? %>
  <div>
    <h2><%= article.errors.count %>件のエラーがあります</h2>
    <ul>
      <% article.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>
画面の例OUTPUT
1件のエラーがあります
Title can't be blank

保存に失敗したときはrender :newでフォームを再表示します。redirect_toを使うと別リクエストになり、モデルのエラー情報が失われるため、入力エラーの再表示には通常renderを使います。

04

Strong Parameters

受け取ったパラメーターの全項目をそのまま保存しません。保存してよい属性をコントローラーで明示します。

controllerRUBY
private

def article_params
  params.require(:article).permit(:title, :body)
end
よくある漏れモデルに列を追加しただけではフォームから保存できません。フォーム、Strong Parameters、モデルのバリデーション、保存処理の4か所がつながっているかを確認します。
05

編集と削除を画面から行う

新規作成と編集は同じ部分テンプレートを使えます。編集画面では既存のArticleを渡すと、フォームヘルパーがPATCH送信の形を作ります。

controllerRUBY
def edit
  @article = Article.find(params[:id])
end

def update
  @article = Article.find(params[:id])
  if @article.update(article_params)
    redirect_to @article
  else
    render :edit, status: :unprocessable_entity
  end
end
edit.html.erbERB
<h1>記事を編集</h1>
<%= render "form", article: @article %>
送信結果OUTPUT
PATCH /articles/3
更新しました
GET /articles/3

保存に失敗したときは同じ編集画面へ戻し、入力値とエラーを失わないようにします。

06

フラッシュメッセージとレイアウト

redirect後に一度だけ表示するメッセージはflashへ入れ、レイアウトで共通表示します。

controllerRUBY
redirect_to articles_path, notice: "記事を削除しました"
redirect_to @article, alert: "保存できませんでした"
app/views/layouts/application.html.erbERB
<% if notice %>
  <p class="notice"><%= notice %></p>
<% end %>
<% if alert %>
  <p class="alert"><%= alert %></p>
<% end %>
表示結果OUTPUT
記事を削除しました
07

フォームの安全性を確認する

入力欄の表示、サーバー側のバリデーション、Strong Parametersは役割が違います。画面のJavaScript検証だけでは不十分なので、必ずモデルとコントローラーでも確認します。

入力値を限定するRUBY
def article_params
  params.require(:article).permit(:title, :body)
end
HTMLを安全に表示ERB
<p><%= article.body %></p>
<!-- html_safeを無条件に使わない -->

利用者が入力したHTMLを許可する機能が必要なら、許可するタグを限定してサニタイズします。表示を簡単にするために安全機構を無効化しないことが重要です。

PRACTICE

練習問題

問題:文字数を表示する

記事本文の文字数を表示し、本文がないときは「本文なし」と表示してください。

解答例ERB
<% if article.body.present? %>
  <p>文字数:<%= article.body.length %></p>
<% else %>
  <p>本文なし</p>
<% end %>