6
6

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 3 years have passed since last update.

【Ruby on Rails】CRUD操作を行うアプリケーションの作成手順

Posted at

【Ruby on Rails】CRUD操作を行うアプリケーションの作成手順

前回、Ruby on Railsを全くゼロの状態からプロジェクトを作成し、DBから取得したデータをブラウザに表示したので、

その続きでアプリケーションにCRUD(作成、読み取り、更新、削除)を実装する方法について。

目次

  1. ルーティングの追加(show)
  2. アクションの追加(show)
  3. ビューの編集(show)
  4. ブラウザに表示
  5. リソースフルルーティング
  6. pathヘルパーを使ったリンク設定
  7. link_toヘルパーへの置き換え
  8. newとcreateアクションの作成
  9. フォームの作成
  10. ストロングパラメータの設定
  11. articlesトップにフォームへのリンクを追加
  12. editとupdateアクションの作成
  13. パーシャル(共有ビュー)の作成
  14. 編集ページへのリンク追加
  15. 削除処理の作成
  16. ボタンリンクのレイアウト調整

## 1. ルーティングの追加(show) まずは、ルーティングを追加する。 config/routes.rbに以下を記述。
routes.rb
Rails.application.routes.draw do
  root "articles#index"

  get "/articles", to: "articles#index"
  get "/articles/:id", to: "articles#show"
end

get "/articles/:id", to: "articles#show"
/articles/整数 のURIのアクセスしたら、articlesコントローラのshowアクションを実行する。

:id
URIに:パラメータ名とすることでデータを渡すことができる。

▼パラメータの受け取り
params([:パラメータ名]) でデータを受け取ることができる。

パラメータ受け渡しの例
ルーティング: /articles/:id
 ↓
URL: articles/5
 ↓
コントローラ: params([:id])  #イコール5になる。

paramsがあったら、getメソッドでデータが渡されているんだな。と理解しておけばOK。


## 2. アクションの追加(show) "articles#show"の処理を作成する。 `app/controllers/articles_controller.rb`に以下を追記。
articles_controller.rb
  def show
    @article = Article.find(params[:id])
  end

テーブルarticlesの中の、URIの末尾で渡された整数番目のデータを取得し、@article(単数形)に代入する。

たくさんあるテーブルのデータのうち1行のみを指定して抜き出しているため、変数名は単数形にしている。

@ の意味
コントローラの中の@変数をインスタンス変数とよび、インスタンス毎に異なる変数を定義できる。

@@変数の場合はクラス変数とよび、クラスで固有(どのインスタンスでも同じ)な変数となる。

(参考)【Ruby】クラスの中のアットマークの意味。@と@@の違いは?


## 3. ビューの編集(show) "articles#show"実行後に表示するビューを作成する。 views > articles > show.html.erb を作成する。
show.html.erb
<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

コントローラのshowアクションで、articlesテーブルから取得したデータ@articleの中のtitlebodyを表示している。

4. ブラウザに表示

http://localhost:3000/articles/1
にアクセスして、ページが正しく表示されるか確認する。

image.png

サーバーが停止している場合は以下で起動。

$ bin/rails server

## 5. リソースフルルーティング CRUD操作のR(読み取り)のためにshowアクションを設定した。 Ruby on Railsには便利なCRUDのための超便利なリソースフルルーティングという機能がある。

routes.rbに以下を記述すると、CRUDのルーティングを自動生成してくれる。

resources :ルート名

なお、ルーティングの確認はbin/rails routesコマンドでできる。


**▼ルーティングの確認**
routes.rb(indexとshow)
Rails.application.routes.draw do
  root "articles#index"
  get "/articles", to: "articles#index"
  get "/articles/:id", to: "articles#show"
end
$ bin/rails routes
                                  Prefix Verb   URI Pattern                                                                                       Controller#Action
                                    root GET    /                                                                                                 articles#index
                                articles GET    /articles(.:format)                                                                               articles#index
                                         GET    /articles/:id(.:format)                                                                           articles#show

↓ リソースフルルーティングに変更

routes.rb(indexとshow)
Rails.application.routes.draw do
  root "articles#index"
  resources :articles
end
$ 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

HTTP動詞にPOSTやDELETE、ルートにnew, :id/editが追加されている。

右の方にスクロールしていくと、index, create, new, edit, show, update, destroyアクションと対応していることがわかる。


## 6. pathヘルパーを使ったリンク設定 リソースフルルーティングを使うと、pathヘルパーも使えるようになる。

ルート名_path(対応するテーブルの行データ)

この記述で、対象のページへのURIを表示することができる。

articlesトップページに各ページへのリンクを追加

resources :articlesでCRUDのルーティングを作成した場合、articles_pathヘルパーが作成される。引数でArticleモデル(articlesテーブル)の1行のデータを渡すと、そのページへのリンクを自動生成してくれる。

これを利用して、index.html.erbページに各個別ページへのリンクを設置する。

index.html.erb
<h1>Articles</h1>

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

articles#indexコントローラから受け取った@articlesのデータを一つづつ抜き出し、article_path(article)で各個別ページへのリンクを生成している。


**▼ブラウザでの表示** http://localhost:3000/articles/
image.png

article.title名でリンクが表示され、クリックすると個別ページに移動することができる。


## 7. link_toヘルパーへの置き換え aタグとpathヘルパー、アンカーテキストの組み合わせは、`link_to`を使うと簡単に記述できる。

link_to "アンカーテキスト", ルート名

index.html.erb
<h1>Articles</h1>

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

**▼ブラウザでの表示** http://localhost:3000/articles/
image.png

pathヘルパーを使った場合と同じ内容が表示される。


## 8. newとcreateアクションの作成 CRUD操作のC(作成)に当たるアクションを作成する。作成するアクションは2つ。(1)データ入力のためのform用にnewアクション。(2)データをDBに保存するためのcreateアクション。

▼newアクション

  • モデルから新しいオブジェクトを作成。
  • formを表示するために使用する(saveではない)
  • 対象のビューは、new.html.erb

▼createアクション

  • 作成した新しいオブジェクトにデータを追加
  • saveでテーブルに保存する目的。
  • save処理がうまくいけば、その記事ページにリダイレクト。/articles/#{@article.id}
  • save処理がうまくいかない場合はnewアクションに飛ばす

app/controllers/articles_controller.rb

articles_controller.rb
  def new
    @article = Article.new
  end

  def create
    @article = Article.new(title: "...", body: "...")

    if @article.save
      redirect_to @article
    else
      render :new
    end

if @article.save
変数.saveはSQLで INSERT INTO~を実行した後、最後にbooleanを返すため、if文の条件式として使うことができる。

render :アクション名
renderでアクション名を指定すると、そのアクションを実行することができる。

redirect_toとrenderの違い

saveが成功したときのページ繊維はredirect_to、失敗したときはrenderヘルパーを使うのには意味がある。

redirect_toは新しいリクエストを作成してページ遷移する。対して、renderは現在のリクエストのまま指定のページを開く

このため、DBのデータに変更があった場合は、新しいリクエストで通信し直す必要があるため、redirect_toを使う。


## 9. フォームの作成 newアクションで開くフォームを作成する。 app/views/articles/new.html.erb
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 %>

image.png

rubyでformを簡単に作るためにヘルパーが用意されている。(form builderと呼ぶ)。

form builderで使うメソッドは、label, text_field(またはtext_area), submitの3つだけ。

form_with

form builderインスタンスを生成する。

フォームビルダー
<%= form_with model: モデルのインスタンス do |form| %>

form.label

入力フォームにラベル(テキスト)をつける。指定は文字列でも、プロパティ名でも可。

プロパティ名で指定
<%= form.label :プロパティ名 %>
文字列で指定
<%= form.label "テキスト" %>
文字列とプロパティ名の組み合わせ
<%= form.label "テスト#{:プロパティ名}テスト" %>

**▼コンパイル例**
<%= form.label :title %>

↓ htmlにコンパイル

<label for="article_title">Title</label>

#### ・`form.text_field` 入力ボックス(input type="text")を作成する。
<%= form.text_field :プロパティ名 %>

コンパイルすると対応するidとname属性が生成される。


**▼コンパイル例**
<%= form.text_field :title %>

↓ htmlにコンパイル

<input type="text" name="article[title]" id="article_title">

#### ・`form.submit` 送信ボタンを作成する。
<%= form.submit %>

↓ htmlにコンパイル

<input type="submit" name="commit" value="Save " data-disable-with="Save ">

デフォルトではSaveの文字が表示される。

image.png

▼文字列の追加とクラスの追加
文字列は " "で記述。
クラス名は,class:'クラス名' ※カンマ必須。(他のヘルパーも同様)

<%= form.submit "送信", class:"submit-button" %>

↓ htmlにコンパイル

<input type="submit" name="commit" value="送信" class="submit-button" data-disable-with="送信">

## 10. ストロングパラメータの設定 悪意のあるユーザーによるDBのデータ追加を防ぐため、コントローラにプライベートメソッドを追加する。

app/controllers/articles_controller.rb

10-1. プライベートメソッドの追加

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

articleオブジェクトで変更・追加できるカラムは、titlebodyのみという制限を付与。


#### (補足)エラー undefined method `errors' 次のようなエラーが発生した場合は、コントローラにプライベートメソッドが追加されていない可能性がある。

undefined method `errors' for nil:NilClass


### 10-2. バリデーションの追加 モデルにバリデーションを追加する。

validates :カラム名, バリデーションルール

app/models/article.rb

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

### 10-3. エラーメッセージの表示設定 バリデーションでfalseになったときのエラーメッセージはビューの中に記述する。
エラーメッセージ
    <% @モデルのインスタンス名.errors.full_messages_for(:プロパティ).each do |message| %>
      <div><%= message %></div>
    <% end %>

app/views/articles/new.html.erb

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 %><br>
    <% @article.errors.full_messages_for(:body).each do |message| %>
      <div><%= message %></div>
    <% end %>
  </div>

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

この状態では、エラーメッセージが設定されていないため表示されない。


## 11. articlesトップにフォームへのリンクを追加 `link_to`ヘルパーを使う。パスはpathヘルパーを使う
<%= link_to "アンカーテキスト", アクション名_インスタンス名_path %>

app/views/articles/index.html.erb
index.html.erb
<h1>Articles</h1>

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

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

## 12. editとupdateアクションの作成 CRUDの「U」(更新)を行うためのアクションを作成する。必要なアクションは2つ。

(1)editアクションで、DBから指定したidのデータを取得して表示する。
(2)updateアクションで、変更内容をDBに反映する。

app/controllers/articles_controller.rb に以下を追記。

articles_controller.rb
  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
    end
  end

・`モデルのインスタンス.update(更新データ)` 更新データとして、article_params関数が渡されている。これは、先ほどストロングパラメータとして定義したもの。

データ更新時にバリデーションを実行して、その結果がupdateの引数(更新データ)になる。

updateの引数にストロングパラメータを指定するのが一般的。

articles_controller.rb(コントローラ)
  private
    def article_params
      params.require(:article).permit(:title, :body)
    end
article.rb(モデル)
class Article < ApplicationRecord
  validates :title, presence: true
  validates :body, presence: true, length: { minimum: 10 }
end

## 13. パーシャル(共有ビュー)の作成 newとeditで使うビューは全く同じものになる。このため、共有用のビュー(パーシャルや部分テンプレートと呼ぶ)を作成して、newとeditそれぞれのビューでパーシャルを読み込むようにする。

13-1. パーシャルの作成

パーシャルのファイル名は冒頭にアンダースコアをつけ、共有用であることがわかるようにする。

呼び出すビューと同じディレクトリに作成する。

app/views/articles/_form.html.erb

_form.html.erb
<%= 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 %><br>
    <% article.errors.full_messages_for(:body).each do |message| %>
      <div><%= message %></div>
    <% end %>
  </div>

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

▼注意点
パーシャルを使わず直接表示した場合、受け取るデータを@をつけて@モデルのインスタンス名で記述したが、パーシャルは@ が不要になる。

これは、パーシャルを呼び出す時に、@ のつかないプロパティ名で渡す記述をするため(次で作成)


### 13-2. パーシャルの呼び出し renderヘルパーを使って、パーシャルを呼び出す。

<%= render "form", 渡すプロパティ名: @モデルのインスタンス名 %>

以下2ファイルでパーシャルを呼び出す記述を追記。

app/views/articles/new.html.erb
app/views/articles/edit.html.erb

new.html.erb
<h1>New Article</h1>

<%= render "form", article: @article %>
edit.html.erb
<h1>Edit Article</h1>

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

どちらのビューも呼び出し方は同じ。h1が異なるのみ。


### 13-3. ブラウザで確認 http://localhost:3000/articles/1/edit にアクセスする。

image.png

DBのデータが表示されていればOK。


## 14. 編集ページへのリンク追加 `link_to`を使って、記事詳細ページ(show)と一覧ページ(index)に編集ページ(edit)へのリンクを追加する。

ページの指定はpathヘルパーを使う。引数でデータを渡す

app/views/articles/show.html.erb

show.html.erb
<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

<ul>
  <li><%= link_to "Edit", edit_article_path(@article) %></li>
</ul>

app/views/articles/index.html.erb
index.html.erb
<h1>Articles</h1>

<ul>
  <% @articles.each do |article| %>
    <li>
      <%= link_to article.title, article %> | <%= link_to "Edit", edit_article_path(article) %>
    </li>
  <% end %>
</ul>

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

## 15. 削除処理の作成 ### 15-1. コントローラにdestroyアクションを追加 CRUDの「D」(削除)処理をコントローラに追加する。

app/controllers/articles_controller.rb

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

    redirect_to root_path
  end

### 15-2. 削除リンクの追加 `button_to`ヘルパーを使って、詳細ページ(show)と一覧ページ(index)に削除リンクを追加する。

削除処理のURLはarticleでshowやupdateアクションと同じ。HTTP動詞でdeleteを選択することで振り分けを行う。

<li><%= button_to "Destroy", article_path(@article), method: :delete} %>

method: :メソッド名
アクセスするメソッドを指定する。デフォルトはGET。

▼注意点
公式のチュートリアルではlink_toが使われているが、GETメソッドで飛んでしまい削除できないため、button_toを使う。

confirmはbutton_toでは機能しない(rails v6)
data: {confirm: 文字列}
リンク先に飛ぶ前に確認ダイアログを表示する。


app/views/articles/show.html.erb
show.html.erb
<h1><%= @article.title %></h1>

<p><%= @article.body %></p>

<ul>
  <li><%= link_to "Edit", edit_article_path(@article) %></li>
  <li><%= button_to "Delete", article_path(@article), method: :delete %></li>
</ul>
image.png

ボタンとリンクが組み合わさって不自然。。


app/views/articles/index.html.erb
index.html.erb
<h1>Articles</h1>

<ul>
  <% @articles.each do |article| %>
    <li>
      <%= link_to article.title, article %> | 
      <%= link_to "Edit", edit_article_path(article) %> | 
      <%= button_to "Delete", article_path(article), method: :delete %>

    </li>
  <% end %>
</ul>

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

## 16. ボタンリンクのレイアウト調整 `button_to`で作成したボタンを、アンカーテキストと同じになるようCSSで調整する。
image.png

コントローラを作成した時に同時に生成されるscssファイルを編集する。

app/assets/stylesheets/articles.scss

button_toをコンパイルしたタグにはclass="button_to"がついているのでそれを利用。

articles.scss
.button_to > input{
  //ボタンのcssをキャンセル
  border: none;
  outline: none;
  background: transparent;

  //リンクのcssに合わせる
  font-size: 16px;
  text-decoration: underline;
  color: #640764;
  padding: 0;
  font-family: initial;
}
image.png

だいたい似た感じになった。(ざっくりなので、カラーコードやhoverの設定など適宜調べてください)


今回はここまで。次回はCommentモデルの生成と、モデルの関連づけ。
6
6
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
6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?