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?

L07:CRUDまとめ

Posted at

1. 目的

  • CRUD(Create/Read/Update/Delete) の 7アクション(index, show, new, create, edit, update, destroy) を一通り体験する。
  • resources が作るルートとパスヘルパ、HTTPメソッド(GET/POST/PATCH/PUT/DELETE) の役割を、テーブル操作の観点で説明できる。
  • Controller での .all / .new / .find / .save / .update / .destroy の使い分けを身につける。

2. ファイル/フォルダ作成

コマンドプロンプト
rails g model l07/tweet title:string body:text
rails g controller l07/tweets index show new edit
  • これで以下が生成されます:
    • db/migrate/*_create_l07_tweets.rb
    • app/models/l07/tweet.rb
    • app/controllers/l07/tweets_controller.rb
    • app/views/l07/tweets/{index,show,new,edit}.html.erb

3. 各ページのつながり(resources/HTTPメソッド/routesの読み方)

3-1. resources が作る7ルート

config/routes.rb
Rails.application.routes.draw do
  namespace :l07 do
    resources :tweets  # ← これ1行で7アクション分のRESTルート
  end
end

パスを確認してみよう!

コマンドプロンプト
rails routes -g tweets
パス メソッド URL Controller#Action 使うパスヘルパ(例)
tweets GET /tweets tweets#index tweets_path(一覧)
tweets POST /tweets tweets#create tweets_path(新規作成の送信先)
new_tweet GET /tweets/new tweets#new new_tweet_path(新規フォーム)
edit_tweet GET /tweets/:id/edit tweets#edit edit_tweet_path(@tweet)(編集フォーム)
tweet GET /tweets/:id tweets#show tweet_path(@tweet)(詳細)
tweet PATCH/PUT /tweets/:id tweets#update tweet_path(@tweet)(更新の送信先)
tweet DELETE /tweets/:id tweets#destroy tweet_path(@tweet)(削除の送信先)

3-2. HTTPメソッドの重要性と機能

  • GET:見るだけ
    • 使う画面: 一覧・詳細・新規フォーム・編集フォーム(index/show/new/edit
    • テーブル: 変化なし(行は増えない・消えない・書き換わらない)
  • POST:新しく作る
    • 使う場面: 新規作成(createPOST /tweets
    • テーブル: 1行追加(title, body などの列に値が入り、新しいIDの行ができる)
  • PATCH:一部を直す
    • 使う場面: 既存の一部変更(updatePATCH /tweets/:id
    • テーブル: 既存1行の一部の列だけが書き換わる
  • PUT:上書きするイメージ
    • 使う場面: API等で全置換的に更新(RailsではPATCHと同じupdateに届く)
    • テーブル: 既存1行が新内容で更新
  • DELETE:消す
    • 使う場面: 削除(destroyDELETE /tweets/:id
    • テーブル: 1行削除(関連設定により子も消えることあり)

4. 解説

4-1. routes.rb

config/routes.rb
Rails.application.routes.draw do                         # ルーティング定義の開始
  namespace :l07 do                                      # /l07 プレフィックス+L07:: 名前空間
    resources :tweets                                    # 7アクションRESTルートを一括定義
  end                                                    # namespace 終了
end                                                      # draw 終了

コードの解説

  • namespace :l07
    • URLを /l07/... にまとめ、対応コントローラは L07:: 名前空間で探す。
  • resources :tweets
    • tweets7アクションのルートとパスヘルパを一括生成

4-2. tweet.rb

app/models/l07/tweet.rb
class L07::Tweet < ApplicationRecord     # L07::Tweet モデル(物理テーブル l07_tweets と対応)
  self.table_name = "l07_tweets"         # 名前空間つきなので物理名を明示
  # バリデーション等は今回は未設定
end

コードの解説

  • self.table_name = "l07_tweets"
    • 名前空間付きでも 物理テーブル名を明示して混乱を防止。

4-3. tweets_controller.rb

app/controllers/l07/tweets_controller.rb
class L07::TweetsController < ApplicationController

  def index
    tweets = L07::Tweet.all
  end

  def new
    @tweet = L07::Tweet.new
  end

  def create
    tweet = L07::Tweet.new(tweet_params)
    if tweet.save
      redirect_to :action => "index"
    else
      redirect_to :action => "new"
    end
  end

  def show
    @tweet = L07::Tweet.find(params[:id])
  end

  def edit
    @tweet = L07::Tweet.find(params[:id])
  end

  def update
    tweet = L07::Tweet.find(params[:id])
    if tweet.update(tweet_params)
      redirect_to :action => "show", :id => tweet.id
    else
      redirect_to :action => "new"
    end
  end

  def destroy
    tweet = L07::Tweet.find(params[:id])
    tweet.destroy
    redirect_to action: :index
  end

  private
  def tweet_params
    params.require(:l07_tweet).permit(:body)
  end
end

コードの解説

  • def とは
    • def ... end
      • 処理のかたまりに名前を付ける。これがメソッド
    • 戻り値
      • 最後に記述された式がそのまま返る(return は省略可)。
  • def index
    • Tweet.all
      • テーブル l07_tweets の全行をまとめて扱う“一覧(コレクション)” を返します。
      • ビュー側で @tweets.each のように ループして使います。
  • def new
    • Tweet.new
      • 仮のレコード(空) を作ります。
      • DBにはまだ書き込まれないので、フォーム表示の初期値として使います(new アクション)。
  • def create
    • Tweet.new(tweet_params)(引数あり)
      • 受け取った値をまとめて tweet_params メソッドにセットして、仮のレコードを作ります。
      • まだDBには書かれません。保存は .save のタイミングです。
    • tweet.save
      • 仮のレコードを DBにINSERT(1行追加) します。
      • 成功なら true、失敗なら false を返します(失敗時は tweet.errors に理由が入ります)。
    • redirect_to :action => "..."
      • 指定アクションへ 別リクエストとして移動(リダイレクト) します。
      • 近年は redirect_to l07_tweets_path のように パスヘルパを使う書き方も一般的です。
  • def show/edit/update/destroy
    • .find(params[:id])
      • URLの :id を使って 既存の1行を取得 します(主キー検索)。
      • 見つからない場合は 例外(404相当) が発生します。show/edit/update/destroy で使います。
  • def update
    • tweet.update(tweet_params)
      • 既存行の属性を まとめて上書きして保存(UPDATE) します。
      • 成功で true、失敗で false を返します(失敗時は tweet.errors を確認)。
  • def destroy
    • tweet.destroy
      • そのレコードを DBから削除 します(1行削除)。
      • 関連を設定している場合は、オプションによって子レコードも連動削除されることがあります。
  • private
    • 以降に定義したメソッドは 外部から呼び出せない(コントローラのアクションにはならない)範囲になります。
    • これにより、tweet_params のような 補助メソッドをアクションとして誤呼び出しされない ように守れます。
    • params.require(:l07_tweet).permit(...)
      • 受け取ったパラメータから、まず require で必須キー(外側の名前) を指定します。
      • その中で permit に書いたキーだけ安全に受け付け ます(それ以外は捨てられる)。

@tweet = Tweet.〇〇tweet = Tweet.〇〇 の違い

  • @tweet(インスタンス変数)
    • ビュー(.html.erb)から見える変数。
    • コントローラ内でセットすると、同じリクエストのビューなどから参照できる。
    • 例:@tweets = Tweet.allindex.html.erb@tweets.each が使える。
  • tweet(ローカル変数)
    • そのメソッドの中だけで使える一時的な変数。
    • ビューからは見えない。tweet に入れてもテンプレート側では参照できない。

役割と使い分け(超実務的ルール)

  • 画面に出したいデータ(一覧・詳細・フォーム初期値)は @... に入れる
    • 例:index/new/show/edit@tweets, @tweet
  • 画面に出さない“処理用の値”(保存・更新・削除だけ)なら ローカル変数で十分。
    • 例:create/update/destroytweet = Tweet.new(...) など

4-4. index.html.erb

app/views/l07/tweets/index.html.erb
<h1>一覧</h1>
<%= link_to "新規作成", new_l07_tweet_path %>
<div class="tweets-container">
  <% @tweets.each do |t| %>
    <div class="tweet">
      <%= t.title %>
      <%= t.body %>
      <%= link_to "詳細", l07_tweet_path(t) %>
    </div>
  <% end %>
</div>

コードの解説

  • @tweets.each
    • 一覧用コレクションをループ表示。
  • l07_tweet_path(t)
    • 詳細ページのパスヘルパ(GET /l07/tweets/:id)。

4-5. show.html.erb

app/views/l07/tweets/show.html.erb
<h1>詳細</h1>
<div class="tweet">
  <p><%= @tweet.title %></p>
  <p><%= @tweet.body %></p>
  <p><%= @tweet.created_at %></p>
  <p><%= link_to "編集", edit_l07_tweet_path(@tweet) %></p>
  <p><%= button_to "削除", l07_tweet_path(@tweet), method: :delete %></p>
</div>

<%= link_to "一覧に戻る", l07_tweets_path %>  

コードの解説

  • @tweet.title / @tweet.body
    • Controller の @tweet を表示。
  • edit_l07_tweet_path(@tweet)
    • 編集フォーム(GET /l07/tweets/:id/edit)。
  • button_to ... method: :delete
    • 削除(DELETE /l07/tweets/:id)。

4-6. new.html.erb

app/views/l07/tweets/new.html.erb
<h1>新規作成</h1>
<%= form_for @tweet do |f| %>

  <div class="field">
    <%= f.label :title %>
    <%= f.text_field :title, :size => 30 %>
  </div>

  <div class="field">
    <%= f.label :body %>
    <%= f.text_area :body, :size => "30x2" %>
  </div>

  <%= f.submit "投稿する" %>
<% end %>

<%= link_to "一覧に戻る", l07_tweets_path %>

コードの解説

  • form_for @tweet
    • 新規(未保存) なので送信先は POST /l07/tweetscreate)。

4-7. edit.html.erb

app/views/l07/tweets/edit.html.erb
<h1>編集</h1>
<%= form_for @tweet do |f| %>

  <div class="field">
    <%= f.label :title %>
    <%= f.text_field :title, :size => 30 %>
  </div>

  <div class="field">
    <%= f.label :body %>
    <%= f.text_area :body, :size => "30x2" %>
  </div>

  <%= f.submit "更新する" %>
<% end %>

<%= link_to "一覧に戻る", l07_tweets_path %>

コードの解説

  • form_for @tweet
    • 保存済みのため送信先は PATCH /l07/tweets/:idupdate)。

5. 動作確認

コマンドプロンプト
rails db:migrate
rails s

1. 一覧を開く: /l07/tweetsエラー①undefined method 'each' for nil:NilClass)を確認
2. エラー①修正: 修正し再読み込み
3. 新規作成: タイトル+本文で投稿 → 一覧に戻る
4. 現象確認: タイトルが未表示
5. エラー②修正: 修正し再読み込み
6. 再作成: 新規作成&編集で title が表示・更新されることを確認

6. エラーの解答

(A) NoMethodError
app/controllers/l07/tweets_controller.rb
 def index
-  tweet = L07::Tweet.all   # ローカル変数
+  @tweet = L07::Tweet.all  # インスタンス変数にする
 end
  • 原因: View は @tweet を参照するのに、Controller が tweet に代入しているため @tweetnil
  • 修正方法: tweet@tweet に直す。
(B) title が表示されない
app/controllers/l07/tweets_controller.rb
 private
 def tweet_params
-  params.require(:tweet).permit(:body)             # NG: title を許可していない
+  params.require(:tweet).permit(:title, :body)     # OK: title を追加
 end
  • 原因: permit に無いキーは捨てられるため、title が保存されない
  • 修正方法: permit:title を追加する。

7. 確認テスト(満点合格)

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?