0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Railsの基礎を使って、メッセージ投稿アプリを作ってみた 【第2章】(3.リファクタリング〜5.バリデーションの設定まで)

Last updated at Posted at 2022-09-05

概要

前回の記事(第1章)で作成したアプリの続きです。
Railsの基礎を使って、メッセージ投稿アプリを作ってみた 【第1章】(1.アプリ作成〜2.CRUD処理まで)

今回の第2章では、コントローラの処理のリファクタリング、ビューファイルを部分テンプレートで共通化、フラッシュメッセージの設定&表示、モデルにバリデーションの追加という流れで進めていきます。

開発環境

  • Ruby 2.7.3
  • Rails 6.1.6.1
  • Postgresql

開発手順

  1. アプリの作成 (第1章)
  2. CRUD処理で簡単なメッセージ投稿アプリを実装 (第1章)
  3. リファクタリング (第2章)
  4. フラッシュの実装 (第2章)
  5. バリデーションの設定 (第2章)
  6. エラーの処理 (第3章)
  7. Bootstrapでスタイルをつける (第4章)

リファクタリング

まずコントローラの処理を見てみると、同じ処理を書いてる箇所が複数見当たります。

app/controllers/posts_controller.rb
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 フィルタを使って、共通化します。

app/controllers/posts_controller.rb
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行目以外同じ内容となってます。

【新規投稿ページ】

app/views/posts/new.html.erb
<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 %>

【編集ページ】

app/views/posts/edit.html.erb
<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 %>

同じ記述をしている部分のみ、別でファイルを作成し、作成したビューファイルをレンダリングする形とします。

【新たに作成したビューファイル】

app/views/posts/_form.html.erb
<%= 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 %>

【新規投稿ページ】

app/views/posts/new.html.erb
<h1>新規投稿</h1>
<%= render "form" %>

【編集ページ】

app/views/posts/edit.html.erb
<h1>編集</h1>
<%= render "form" %>

ここで注意したいのが、

  • 新たに作成したファイルはファイル名の最初を _ から始まるようにすること。今回は_form.html.erb
  • レンダリングする際は、<%= render "form" %>のように _ は付けないこと。

これで部分テンプレートは完成しましたが、新規投稿ページでも編集ページでも送信ボタンとなっています。
新規投稿ページでは送信ボタン、編集ページでは更新ボタンと表示されるよう変数を使用します。

まず、_form.html.erb<%= form.submit "送信" %> button_name とし、変数に変更します。

app/views/posts/_form.html.erb
<%= 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.erbedit.html.erbで変数を定義して完成です。

app/views/posts/new.html.erb
<h1>新規投稿</h1>
<%= render "form", button_name: "投稿" %>
app/views/posts/edit.html.erb
<h1>編集</h1>
<%= render "form", button_name: "更新" %>

最後に、前章の最初で作成した全ページに表示されるリンクも、新たに別ファイルを作成し、レンダリングする形とします。

【新たに作成したファイル】

app/views/layouts/_header.html.erb
<%= link_to "投稿一覧", posts_path %> <%= link_to "新規投稿" new_post_path %>

<%= render "layouts/header" %>とし、上記で作成したファイルをレンダリング。

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  
<!-- 略 -->

  <body>
    <%= render "layouts/header" %>
    <%= yield %>
  </body>
</html>

app/views/layouts/application.html.erbでレンダリングさせる場合は、必ず<%= render "header" %>ではなく、<%= render "layouts/header" %>にしないとエラーが出るので注意して下さい。

これでビューファイルの部分テンプレートは完了です。
ここで一度サーバーを起動し、問題なく機能するか確認することをお勧めします。

フラッシュ

投稿、更新、削除した際は以下のようにリダイレクトするようになっています。
新規投稿後 → 投稿詳細ページ
編集ページで更新後 → 投稿一覧ページ
投稿一覧で削除後 → 投稿一覧ページ

このままだと、しっかり投稿できているのか、更新、削除できているのかと不安に思う方もいると思うので、投稿しました削除しましたなどメッセージが表示されるようにフラッシュメッセージを追加し、表示する作業に入ります。

フラッシュメッセージを追加するには、以下の2点の作業が必要です。

  1. コントローラでフラッシュメッセージの設定
  2. ビューでフラッシュメッセージの表示

まずはコントローラの方から進めていきます。

app/controllers/posts_controller.rb
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に記述し、レンダリングする形とします。

【新たに作成したファイル】

app/views/layouts/_flash.html.erb
<% flash.each do |flash_type, msg| %>
  <p><%= msg %></p>
  <hr>
<% end %>
app/views/layouts/application.html.erb
<!-- 略 -->

 <body>
    <%= render "layouts/header" %>
    <%= render "layouts/flash" %>
    <%= yield %>
  </body>
</html>

フラッシュを表示させるだけであれば、<%= flash[:notice] %><%= flash[:alert] %>で表示されます。
今回は、両方を共通化させるために、each メソッドを使用します。

これでフラッシュメッセージの設定&表示は完了です。
実際に、サーバーを起動し、新規投稿をした際や更新、削除した際、フラッシュメッセージが表示されているか確認することをお勧めします。

バリデーションの追加

バリデーションとは、データベースに何かを保存する際に、事前に内容を検証する機能です。
例で挙げると、メールアドレスを登録する際、すでに登録されていた場合は、「こちらのアドレスはすでに登録済みです」と表示されることがあると思います。
これらは事前にバリデーションを定義しておくことで働く機能となります。

現在作成しているアプリでも、空文字で投稿できてしまったり、文字数制限がない状態です。
なので、データベースとやり取りをするモデルに以下のバリデーションを追加します。

  • タイトル、内容共に空文字投稿禁止
  • タイトルは50文字以下、内容は500文字以下
app/models/post.rb
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章では、バリデーションを設定したことによって発生するエラーの処理を変更し、エラーメッセージを表示させる作業に入ります。

お疲れ様でした!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?