FullStackEngineer 2022年2月6日更新

CRUDについて

Index

一週間のカリキュラム 1週間で、Ruby 〜 Ruby on Rails までを学ぶ

シリーズの3日目、データを読み書きする、CRUD について見ていきます。

3日目の内容


CRUD は全てのアプリケーションの基本

CRUD とは

  • Create
  • Read
  • Update
  • Delete

の略称です。

ブログのような機能を考えるのならば

  • 記事の作成、更新、削除
  • 記事のリスト表示(+検索表示)、記事単体の表示

は必須の機能です。 ほとんどのフレームワークでは、この機能をなるべく少ない工程で実装できるように機能が作られています。

必要な準備

すでに記事全体を表示する機能は、前回作成してありますので、そこからの続きとなります。

まずはテンプレートは無視して URLのrouteと、それに対応するコントローラーのみを作成します。

./config/route.rb

Rails.application.routes.draw do
  #get 'articles/index'
  root "articles#index"
  resources :articles
end

./app/controllers/articles_controller.rb にも大量ですが、下記のようなメソッドを追加しましょう。

class ArticlesController < ApplicationController

  def index
    @articles = Article.all()
  end

  #ここから追加

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

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(article_params)

    if @article.save
      redirect_to @article
    else
      render :new, status: :unprocessable_entity
    end
  end

  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

def destroy
    @article = Article.find(params[:id])
    @article.destroy

    redirect_to root_path, status: :see_other
  end

  private
    def article_params
      params.require(:article).permit(:title, :body)
    end

end

ここまで入力して下記のようにURLを確認してみましょう。

http://localhost:3000/

前回(http://localhost:3000/articles/index)で表示された内容と同じ内容が表示されると思います。 これはroute(一番上の階層)にarticle#indexコントローラーを追加した結果です。

  root "articles#index" #この部分

では残りの

  resources :articles

の部分はどんなコントローラーと紐付いてるのでしょうか? どのようなURLが作成されたかは以下のコマンドで確認します。


$ bin/rails routes Prefix Verb URI Pattern Controller#Action root GET / articles#index articles GET /articles(.:format) articles#index POST /articles(.:format) articles#create new_article GET /articles/new(.:format) articles#new edit_article GET /articles/:id/edit(.:format) articles#edit article GET /articles/:id(.:format) articles#show PATCH /articles/:id(.:format) articles#update PUT /articles/:id(.:format) articles#update DELETE /articles/:id(.:format) articles#destroy

色々なURLが、どのコントローラーメソッドと紐付いてるかが確認できると思います。

resourcesで追加された コントローラー & テンプレートを一つづつ確認、設定していく。

もう一度 resources :articlesの部分を確認します。


$ bin/rails routes Prefix Verb URI Pattern Controller#Action #0 リスト部分 root GET / articles#index #1 単独記事を表示する。 articles GET /articles(.:format) articles#index #2 新規作成保存 POST /articles(.:format) articles#create #3 新規作成の開始 new_article GET /articles/new(.:format) articles#new #4 再編集の開始 edit_article GET /articles/:id/edit(.:format) articles#edit article GET /articles/:id(.:format) articles#show #5 アップデート処理 PATCH /articles/:id(.:format) articles#update PUT /articles/:id(.:format) articles#update #6 削除 DELETE /articles/:id(.:format) articles#destroy

1 単独記事を表示する。

    articles GET    /articles(.:format)            articles#index

対となるコントローラー

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

これは /articles/1 などとアクセスされた場合を指します。

対応するテンプレートを設置しましょう。

./app/views/articles/show.html.erb

<h1><%= @article.title %></h1>

<%= @article.body %>

これで http://127.0.0.1:3000/articles/1 に記事1のタイトルと内容が表示されました。

このままでは、記事単独ページへのリンクがありませんので、リストページにリンクを追加します。

./app/views/articles/index.html.erb

<h1>Articles</h1>

<ul>
    <% @articles.each do |article| %>
        <li>
            <a href="<%= article_path(article) %>">
                <%= article.title %>
            </a>
        </li>
    <% end %>
</ul>

※モデルやコントローラーがRailsの指定する命名規則に沿っていれば article_path(article)でリンク先URLが出力されます。

また、上記のテンプレートは link_to メソッドを利用することで下記のようにも表現できます。

<h1>Articles</h1>

<ul>
    <% @articles.each do |article| %>
        <li>
            <%= link_to article.title, article %>
        </li>
    <% end %>
</ul>

表記として()が省略された形です。 link_to(文字列,モデル名) ↓ link_to 文字列,モデル名

2 新規作成保存

POST   /articles(.:format)            articles#create 

対応するコントローラーは

  def create
    @article = Article.new(article_params)

    if @article.save
      redirect_to @article
    else
      render :new, status: :unprocessable_entity
    end
  end

この部分に関してはテンプレートがありません。

次に紹介する 3新規作成テンプレートから保存をした時に対応するPOST先となってます。

3 新規作成の開始

 new_article GET    /articles/new(.:format)        articles#new

テンプレートは ./app/views/articles/new.html.erb


<h1>New Article</h1> <%= form_with model: @article do |form| %> <div> <%= form.label :title %><br> <%= form.text_field :title %> </div> <div> <%= form.label :body %><br> <%= form.text_area :body %> </div> <div> <%= form.submit %> </div> <% end %>

これで http://127.0.0.1:3000/articles/new

を開くと新しい記事を追加できるようになります。

しかしこのままだとデータが全て空でも保存が出来てしまいます。 モデルにタイトルを必須にして、記事内容も最低10文字以上いれないと保存できないように 設定します。

app/models/article.rb

class Article < ApplicationRecord
  validates :title, presence: true
  validates :body, presence: true, length: { minimum: 10 }
end

また、エラーメッセージを出せるよう ./app/views/articles/new.html.erb に下記を追加します。

<h1>New Article</h1>

<%= form_with model: @article do |form| %>
  <div>
    <%= form.label :title %><br>
    <%= form.text_field :title %>

    <%# この部分を追加 %>
    <% @article.errors.full_messages_for(:title).each do |message| %>
      <div><%= message %></div>
    <% end %>

  </div>

  <div>
    <%= form.label :body %><br>
    <%= form.text_area :body %>

    <%# この部分を追加 %>
    <% @article.errors.full_messages_for(:body).each do |message| %>
      <div><%= message %></div>
    <% end %>
  </div>

  <div>
    <%= form.submit %>
  </div>
<% end %>

最後に新規作成ページの導線をリストページに追加しましょう


<%= link_to "New Article", new_article_path %>

4 再編集の開始

次に一度作成した記事の編集です。

edit_article GET    /articles/:id/edit(.:format)   articles#edit

コントローラー部分

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

ほぼshowと同じです。 テンプレートですが、newと内容は同じで大丈夫です。 ただ、同じ処理を2箇所にのせるのも非効率なので、共通部分を renderメソッドで、読み込むようにします。

new.htm.erb をコピーして _form.html.erbを作る
$ cp new.html.erb _form.html.erb

new.html.erb edit.html.erb ともに下記の内容にしましょう。

<%= render "form", article: @article %>

これで編集用のテンプレートも準備できました。 編集用のテンプレートへの導線を作る前に削除部分も確認します。

6 削除

DELETE /articles/:id(.:format)        articles#destroy

削除のURLもPOST専用でテンプレートは必要ありません。 先ほどのUPDATE用の導線も含め show.edit.erb部分に導線を作ります。

show.html.erb


<h1><%= @article.title %></h1> <p><%= @article.body %></p> <ul> <%# 編集用導線 %> <li><%= link_to "Edit", edit_article_path(@article) %></li> <%# 削除用導線 %> <li><%= link_to "Destroy", article_path(@article), data: { turbo_method: :delete, turbo_confirm: "Are you sure?" } %></li> </ul>

CRUD機能の後は・・・

今回は基本中の基本を抑えました。

今回実装してない機能として

  • ページング
  • 検索
  • 他のデータとのリレーション(記事にコメントをつけるとか) などがあります。

最新記事一覧

続きを見る

関連コンテンツ

カテゴリー一覧

TOP フルスタックエンジニアを目指すに方々へ 2022年3月12日 Kaminariのbootstrap5 対応