概要
前回の記事(第1章)で作成したアプリの続きです。
Railsの基礎を使って、メッセージ投稿アプリを作ってみた 【第1章】(1.アプリ作成〜2.CRUD処理まで)
今回の第2章では、コントローラの処理のリファクタリング、ビューファイルを部分テンプレートで共通化、フラッシュメッセージの設定&表示、モデルにバリデーションの追加という流れで進めていきます。
開発環境
- Ruby 2.7.3
- Rails 6.1.6.1
- Postgresql
開発手順
- アプリの作成 (第1章)
- CRUD処理で簡単なメッセージ投稿アプリを実装 (第1章)
- リファクタリング (第2章)
- フラッシュの実装 (第2章)
- バリデーションの設定 (第2章)
- エラーの処理 (第3章)
- Bootstrapでスタイルをつける (第4章)
リファクタリング
まずコントローラの処理を見てみると、同じ処理を書いてる箇所が複数見当たります。
class PostsController < ApplicationController
def new
@post = Post.new
end
def create
post = Post.create!(post_params)
redirect_to post_path(post)
end
def index
@post = Post.order(id: :asc)
end
def show
@post = Post.find(params[:id])
end
def edit
@post = Post.find(params[:id])
end
def update
post = Post.find(params[:id])
post.update!(post_params)
redirect_to post_path(post)
end
def destroy
post = Post.find(params[:id])
post.destroy!
redirect_to root_path
end
private
def post_params
params.require(:post).permit(:title, :content)
end
end
@post = Post.find(params[:id])
が2箇所、post = Post.find(params[:id])
が2箇所あります。
複数箇所に同じ処理をかくと、修正が必要になったときに、全て変更することになり、手間もかかります。
なので今回は before_action フィルタを使って、共通化します。
class PostsController < ApplicationController
before_action :set_post, only: %i[show edit update destroy]
def new
@post = Post.new
end
def create
post = Post.create!(post_params)
redirect_to post_path(post)
end
def index
@post = Post.order(id: :asc)
end
def show
end
def edit
end
def update
@post.update!(post_params)
redirect_to post_path(post)
end
def destroy
@post.destroy!
redirect_to root_path
end
private
def set_post
@post = Post.find(params[:id])
end
# 略
end
before_acrion :メソッド名
と記述することにより、指定したアクションの前にメソッドを指定することが可能となります。
メソッド名は private にset_post
を定義し、同じ処理を書いていたところを修正。
また、 update 、 destroy に関しては、ビューファイルに変数を渡す必要がなかったので、 @ のない変数を利用してましたが、共通化するために、 @ をつけた変数に変更。
これで、コントローラのリファクタリングは完了です。
次にビューファイルを見てみると、新規投稿ページ(new.html.erb
)と編集ページ(edit.html.erb
)が1行目以外同じ内容となってます。
【新規投稿ページ】
<h1>新規投稿</h1>
<%= form_with model: @post, local: true do |form| %>
<div>
<%= form.label :title, "タイトル" %>
<%= form.text_field :title %>
</div>
<div>
<%= form.label :content, "内容" %>
<%= form.text_field :content %>
</div>
<div>
<%= form.submit "送信" %>
</div>
<% end %>
【編集ページ】
<h1>編集</h1>
<%= form_with model: @post, local: true do |form| %>
<div>
<%= form.label :title, "タイトル" %>
<%= form.text_field :title %>
</div>
<div>
<%= form.label :content, "内容" %>
<%= form.text_field :content %>
</div>
<div>
<%= form.submit "送信" %>
</div>
<% end %>
同じ記述をしている部分のみ、別でファイルを作成し、作成したビューファイルをレンダリングする形とします。
【新たに作成したビューファイル】
<%= form_with model: @post, local: true do |form| %>
<div>
<%= form.label :title, "タイトル" %>
<%= form.text_field :title %>
</div>
<div>
<%= form.label :content, "内容" %>
<%= form.text_field :content %>
</div>
<div>
<%= form.submit "送信" %>
</div>
<% end %>
【新規投稿ページ】
<h1>新規投稿</h1>
<%= render "form" %>
【編集ページ】
<h1>編集</h1>
<%= render "form" %>
ここで注意したいのが、
- 新たに作成したファイルはファイル名の最初を _ から始まるようにすること。今回は
_form.html.erb
- レンダリングする際は、<%= render "form" %>のように _ は付けないこと。
これで部分テンプレートは完成しましたが、新規投稿ページでも編集ページでも送信ボタンとなっています。
新規投稿ページでは送信ボタン、編集ページでは更新ボタンと表示されるよう変数を使用します。
まず、_form.html.erb
の<%= form.submit "送信" %>
を button_name とし、変数に変更します。
<%= form_with model: @post, local: true do |form| %>
<div>
<%= form.label :title, "タイトル" %>
<%= form.text_field :title %>
</div>
<div>
<%= form.label :content, "内容" %>
<%= form.text_field :content %>
</div>
<div>
<%= form.submit button_name %>
</div>
<% end %>
次に、new.html.erb
とedit.html.erb
で変数を定義して完成です。
<h1>新規投稿</h1>
<%= render "form", button_name: "投稿" %>
<h1>編集</h1>
<%= render "form", button_name: "更新" %>
最後に、前章の最初で作成した全ページに表示されるリンクも、新たに別ファイルを作成し、レンダリングする形とします。
【新たに作成したファイル】
<%= link_to "投稿一覧", posts_path %> <%= link_to "新規投稿" new_post_path %>
<%= render "layouts/header" %>
とし、上記で作成したファイルをレンダリング。
<!DOCTYPE html>
<html>
<!-- 略 -->
<body>
<%= render "layouts/header" %>
<%= yield %>
</body>
</html>
app/views/layouts/application.html.erb
でレンダリングさせる場合は、必ず<%= render "header" %>
ではなく、<%= render "layouts/header" %>
にしないとエラーが出るので注意して下さい。
これでビューファイルの部分テンプレートは完了です。
ここで一度サーバーを起動し、問題なく機能するか確認することをお勧めします。
フラッシュ
投稿、更新、削除した際は以下のようにリダイレクトするようになっています。
新規投稿後 → 投稿詳細ページ
編集ページで更新後 → 投稿一覧ページ
投稿一覧で削除後 → 投稿一覧ページ
このままだと、しっかり投稿できているのか、更新、削除できているのかと不安に思う方もいると思うので、投稿しましたや削除しましたなどメッセージが表示されるようにフラッシュメッセージを追加し、表示する作業に入ります。
フラッシュメッセージを追加するには、以下の2点の作業が必要です。
- コントローラでフラッシュメッセージの設定
- ビューでフラッシュメッセージの表示
まずはコントローラの方から進めていきます。
class PostsController < ApplicationController
# 略
def create
post = Post.create!(post_params)
redirect_to post_path(post),notice: "投稿しました"
end
# 略
def update
post = Post.find(params[:id])
post.update!(post_params)
redirect_to post_path(post), notice: "更新しました"
end
def destroy
post = Post.find(params[:id])
post.destroy!
redirect_to root_path, notice: "削除しました"
end
# 略
今回はリダイレクトと併用するので notice: "メッセージ" とします。
リダイレクトと併用しない場合はflash[:notice] = "メッセージ"と書きます。
これで、コントローラのフラッシュメッセージの設定は完了です。
次にビューファイルでのフラッシュメッセージの表示に進みます。
全ページで使用できるように、app/views/layouts/application.html.erb
に記述し、レンダリングする形とします。
【新たに作成したファイル】
<% flash.each do |flash_type, msg| %>
<p><%= msg %></p>
<hr>
<% end %>
<!-- 略 -->
<body>
<%= render "layouts/header" %>
<%= render "layouts/flash" %>
<%= yield %>
</body>
</html>
フラッシュを表示させるだけであれば、<%= flash[:notice] %>
、<%= flash[:alert] %>
で表示されます。
今回は、両方を共通化させるために、each メソッドを使用します。
これでフラッシュメッセージの設定&表示は完了です。
実際に、サーバーを起動し、新規投稿をした際や更新、削除した際、フラッシュメッセージが表示されているか確認することをお勧めします。
バリデーションの追加
バリデーションとは、データベースに何かを保存する際に、事前に内容を検証する機能です。
例で挙げると、メールアドレスを登録する際、すでに登録されていた場合は、「こちらのアドレスはすでに登録済みです」と表示されることがあると思います。
これらは事前にバリデーションを定義しておくことで働く機能となります。
現在作成しているアプリでも、空文字で投稿できてしまったり、文字数制限がない状態です。
なので、データベースとやり取りをするモデルに以下のバリデーションを追加します。
- タイトル、内容共に空文字投稿禁止
- タイトルは50文字以下、内容は500文字以下
class Post < ApplicationRecord
validates :title, presence: true, length: { maximum: 50 }
validates :content, presence: true, length: { maximum: 500 }
end
コンソールを起動して、以下を入力し、実際に機能しているか確認してみましょう。
Post.create!(title: "", content: "")
Post.create!(title: "テスト", content: "")
Post.create!(title: "", cotent: "テスト")
Post.create!(title: "1" * 51, content: "テスト")
Post.create!(title: "テスト", content: "2" * 501)
確認後、Validation failed
とエラーメッセージがターミナルに表示されることが確認できればOKです。
これでバリデーションの設定は完了となります。
次回の第3章では、バリデーションを設定したことによって発生するエラーの処理を変更し、エラーメッセージを表示させる作業に入ります。
お疲れ様でした!