1
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?

RailsでCRUDを実装してみた話(投資記録アプリ開発ログ)

1
Posted at

はじめに

RUNTEQでの学習の一環として、日本株の投資記録を残せるミニアプリを作っています。

前回までの記事で、マイグレーションとバリデーションについて書いてきましたが、今回は「CRUD」を実際に実装してみて学んだことをまとめてみようと思います。

正直、CRUDという言葉自体は知っていたのですが、「new と create って何が違うの?」「edit と update は別々に用意する意味あるの?」みたいなところがふわっとしたまま進めていたので、自分の頭の整理も兼ねて書いていきます。

作っているアプリについて

日本株の売買記録(銘柄名・株数・価格・売買日・売買理由)を残せる、投資記録アプリを作っています。

「なぜこの株を買ったんだっけ?」を後から振り返れないという自分の悩みを解決するために作り始めました。

CRUDって結局何なのか

CRUDとは、以下の4つの頭文字みたいです。

  • Create(作る)
  • Read(読む)
  • Update(更新する)
  • Delete(消す)

Railsではこれを、コントローラーの7つのアクション(index, show, new, create, edit, update, destroy)で表現するのが基本形になっているようです。

最初、この7つ全部いる?と思ったのですが、実際に手を動かしてみると役割がちゃんと分かれていて納得感がありました。

new と create の違いでつまずいた話

一番最初に「あれ?」となったのがここでした。

def new
  @trade = current_user.trades.build
end

def create
  @trade = current_user.trades.build(trade_params)
  if @trade.save
    redirect_to @trade, notice: "取引記録を登録しました"
  else
    render :new, status: :unprocessable_entity
  end
end

最初は「同じようなことしてるのに何で2つに分かれてるんだろう」と思っていたのですが、書きながら理解が深まりました。

  • new は、空っぽの入力フォームを表示するだけの係
  • create は、フォームが送信された後に、実際に保存する

newの方はデータベースに何も保存しません。ただ画面に空のフォームを出すためだけの処理みたいです。実際に保存が走るのはcreateが呼ばれたときだけ、という役割分担になっていることが分かりました。

editupdateの関係も全く同じ考え方で、editが表示担当、updateが保存担当という構造になっていました。

自分のデータしか見れないようにする工夫

これは実装していて「なるほど」と思った部分です。

def show
  @trade = current_user.trades.find(params[:id])
end

最初、Trade.find(params[:id])と書いてしまいそうになったのですが、これだとURLの数字を変えるだけで他人の取引記録が見えてしまう可能性があるとのことでした。

current_user.trades.find(params[:id])と書くことで、「今ログインしている人の記録の中からだけ探す」という絞り込みになるみたいです。これはUserモデル側にhas_many :tradesがあることで成り立っている書き方らしく、アソシエーションの大事さを実感しました。

ルーティングも整理した

# 変更前
resources :trades, only: [:index]

# 変更後
resources :trades

only: [:index]を外すだけで、一覧・詳細・新規登録・保存・編集・更新・削除の7種類のURLが一気に使えるようになりました。地味ですが、この1行の意味がちゃんと分かると気持ちいいなと思いました。

フォームを共通化してみた

neweditって見た目がほぼ同じフォームだったので、_form.html.erbという部品として切り出して、両方から呼び出す形にしました。

<%= form_with model: @trade, local: true do |f| %>
  <%= f.label :stock_name, "銘柄名" %>
  <%= f.text_field :stock_name %>

  <%= f.label :trade_type, "売買区分" %>
  <%= f.select :trade_type, Trade.trade_types.keys.map { |t| [t == "buy" ? "買い" : "売り", t] } %>

  <%= f.submit %>
<% end %>

form_with model: @tradeと書くと、@tradeが新規なのか既存のレコードなのかをRailsが自動で判断して、送信先(新規登録用か更新用か)を勝手に切り替えてくれるみたいです。これのおかげで、同じ_form.html.erbneweditの両方から使い回せています。

バリデーションエラーの表示も忘れずに

<% if @trade.errors.any? %>
  <ul>
    <% @trade.errors.full_messages.each do |message| %>
      <li><%= message %></li>
    <% end %>
  </ul>
<% end %>

保存に失敗したときにエラーメッセージが表示される仕組みも、_form.html.erbの中に組み込みました。空欄のまま登録しようとすると「銘柄名を入力してください」のようなメッセージが出るようになって、地味に感動しました。

つまずいたポイントまとめ

  • new/createの役割分担が最初分からなかった → 表示担当と保存担当、と覚えたら腑に落ちた
  • Trade.findcurrent_user.trades.findの違いを意識していなかった → セキュリティに直結する部分だと知って重要さを実感
  • フォームの共通化(_form.html.erb)は最初「別々に書けばいいのでは」と思っていたが、修正が1箇所で済むメリットに後から気づいた

おわりに

CRUDという単語だけ知っていても、実際に手を動かして「なぜ7つのアクションに分かれているのか」を体感すると理解が全然違うなと感じました。

もし間違っている理解があれば、ぜひコメントで指摘していただけると嬉しいです。

1
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
1
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?