17
16

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 初学者がECサイトの注文機能について復習

Last updated at Posted at 2021-08-28

この記事を書いた目的

  • Railsを学びはじめて2ヶ月目。プログラミング学習も2ヶ月目の初学者が復習を兼ねて躓いた部分を投稿します。

  • 間違っている部分がありましたらご指摘をお願いいたします。

  • 追記
    今見返すと色々無駄が多いです。
    必要ない記述とかあってお恥ずかしい限りですが、自身がこれだけわかっていなかったんだということでこのままにしておきます。

行いたいこと

  • 顧客は購入するときに配送先を選ぶことができ、新規登録も出来る
    • このときにどうやって値を保持すれば良いのか分からなかったのでそれを復習します
    • session は理解不足なので使いません

用意するもの・使用したバージョン

使用するもの バージョン
Ruby 2.6.3
Rails 5.2.5
作成するテーブル 内容
Customer 顧客データ
Address 顧客の配送先データ
Item 商品データ
CartItem 商品をカートに入れる
Order 注文情報の記録
OrderItem 商品ごとの個別の注文情報
Customer データ型 配送先住所のテーブル
name string ユーザーの名前
customer_address string 初回登録時の配送先住所
Address データ型 追加の配送先住所のテーブル
customer_id FK integer Customerとの関連付け
address_name string 追加の配送先の宛先
address string 追加の配送先住所
Item データ型 商品に関するテーブル
item_name string 商品名
price integer 金額
CartItem データ型 カートに追加した商品のテーブル
customer_id FK integer Customerとの関連付け
item_id FK integer Itemとの関連付け
quantity integer 購入個数
Order データ型 注文情報を保存するテーブル
customer_id FK integer Customerとの関連付け
order_name string 注文時の宛先
order_address string 配送先住所
total_price integer 合計金額
OrderItem データ型 商品ごとの注文情報を保存するテーブル
item_id FK integer Itemとの関連付け
order_id FK integer Orderとの関連付け
order_quantity integer 購入個数
order_price integer 商品ごとの小計

今回はわかりやすさ重視ですべてのカラム名を分けています。
Customer は device を使用しましたが device については割愛します
カラムは動作を確認するための最低限のものです

実際の記述

  • 前提事項
    • カートにはすでに関連付けられた商品が入っているものとします
    • 簡素化するために今回は税込みなどは考えません
    • それぞれのカラムは Not Null 制約を行っているものとします

model

customer.rb
has_many :addresses
has_many :cart_items
has_many :orders
address.rb
belongs_to :customer
item.rb
has_many :cart_items
has_many :order_items
cart_item.rb
belongs_to :order
belongs_to :item

def sum_price # 実際に作成したサイトは税金も算出していたのでメソッドを記載していました
  item.taxin_price*quantity
end

合計金額を算出するメソッドについてはこちらを参考にしました。
カート機能①カート内商品の合計金額を出す inject 税込価格の表示 / ECサイト

order.rb
belongs_to :customer
has_many :order_items
order_item.rb
belongs_to :order
belongs_to :item

controller

orders_controller.rb
# 購入情報の入力画面で、宛先や住所などを入力するところです
def new
  @order = Order.new
end

# 購入を確定します
def create # Order に情報を保存します
  cart_items = current_customer.cart_items.all
# ログインユーザーのカートアイテムをすべて取り出して cart_items に入れます
  @order = current_customer.orders.new(order_params)
# 渡ってきた値を @order に入れます
  if @order.save
# ここに至るまでの間にチェックは済ませていますが、念の為IF文で分岐させています
    cart_items.each do |cart|
# 取り出したカートアイテムの数繰り返します
# order_item にも一緒にデータを保存する必要があるのでここで保存します
      order_item = OrderItem.new
      order_item.item_id = cart.item_id
      order_item.order_id = @order.id
      order_item.order_quantity = cart.quantity
# 購入が完了したらカート情報は削除するのでこちらに保存します
      order_item.order_price = cart.item.price
# カート情報を削除するので item との紐付けが切れる前に保存します
      order_item.save
    end
    redirect_to 遷移したいページのパス
    cart_items.destroy_all
# ユーザーに関連するカートのデータ(購入したデータ)をすべて削除します(カートを空にする)
  else
    @order = Order.new(order_params)
    render :new
  end
end

# new 画面から渡ってきたデータをユーザーに確認してもらいます
def check
  @order = Order.new(order_params)
# new 画面から渡ってきたデータを @order に入れます
  if params[:order][:address_number] == "1"
# view で定義している address_number が"1"だったときにこの処理を実行します
# form_with で @order で送っているので、order に紐付いた address_number となります。以下同様です
# この辺の紐付けは勉強不足なので gem の pry-byebug を使って確認しながら行いました
    @order.name = current_customer.name # @order の各カラムに必要なものを入れます
    @order.address = current_customer.customer_address
  elsif params[:order][:address_number] == "2"
# view で定義している address_number が"2"だったときにこの処理を実行します
    if Address.exists?(name: params[:order][:registered])
# registered は viwe で定義しています
      @order.name = Address.find(params[:order][:registered]).name
      @order.address = Address.find(params[:order][:registered]).address
    else
      render :new
# 既存のデータを使っていますのでありえないですが、万が一データが足りない場合は new を render します
    end
  elsif params[:order][:address_number] == "3"
# view で定義している address_number が"3"だったときにこの処理を実行します
    address_new = current_customer.addresses.new(address_params)
    if address_new.save # 確定前(確認画面)で save してしまうことになりますが、私の知識の限界でした
    else
      render :new
# ここに渡ってくるデータはユーザーで新規追加してもらうので、入力不足の場合は new に戻します
    end
  else
    redirect_to 遷移したいページ # ありえないですが、万が一当てはまらないデータが渡ってきた場合の処理です
  end
  @cart_items = current_customer.cart_items.all # カートアイテムの情報をユーザーに確認してもらうために使用します
  @total = @cart_items.inject(0) { |sum, item| sum + item.sum_price }
# 合計金額を出す処理です sum_price はモデルで定義したメソッドです
end

private

def order_params
  params.require(:order).permit(:name, :address, :total_price)
end

def address_params
  params.require(:order).permit(:name, :address)
end

view

レイアウトは調整していません

orders/new.html.erb
<!-- @order でラジオボタンを使って情報を送ります -->
<%= form_with model: @order, url: check アクションにつながるパス, local: true do |f| %>
<!-- customer テーブルに登録されている住所の場合です -->
  <%= f.radio_button :address_number, 1 %> <!-- address_number と定義して1~3の番号を check に送ります -->
  <%= f.label :address_number_1, "ご自身の住所" %>
  <%= current_customer.customer_address %>

<!-- 登録されたaddressから選んでもらう場合です -->
  <%= f.radio_button :address_number, 2 %>
  <%= f.label :address_number_2, "登録先の住所" %>
  <%= f.collection_select(:registered, current_customer.addresses.all, :id, :address %>
<!-- registered として current_customer.address.all で取得した id を送ります。
     ユーザーに表示して選択してもらうのは address です -->
<!-- ドロップダウンを選択したら自動でラベルも選択されるようにしたかったのですが、現状ではわかりませんでした -->

<!-- 新しい住所を追加する場合です -->
  <%= f.radio_button :address_number, 3 %>
  <%= f.label :address_number_3, "新しいお届け先" %>
  <%= f.label :address, "住所" %>
  <%= f.text_field :address %>
  <%= f.label :address_name, "宛名" %>
  <%= f.text_field :address_name %>
<!-- 選んでもらったデータを送ります -->
  <%= f.submit "確認画面へ進む" %>
<% end %>
orders/check.html.erb
<!-- ユーザーに確認してもらうための表示です -->
<% @cart_items.each do |cart| %>
  <%= cart.item.name %> <!-- 商品名 -->
  <%= (cart.item.price).to_s(:delimited) %> <!-- 金額 -->
  <%= cart.quantity %> <!-- 個数 -->
  <%= (cart.item.price*cart.quantity).to_s(:delimited) %> <!-- 小計 -->
<% end %>
<p>ご請求金額</p>
<%= @total.to_s(:delimited) %> <!-- お買い物の合計金額 -->
<p>お届け先</p>
<%= @order.address %>

<!-- ユーザーには注文確定ボタンだけ表示します -->
<%= form_with model: @order, url: create へのパス, local: true do |f| %>
  <%= f.hidden_field :name %>
  <%= f.hidden_field :address %>
  <%= f.hidden_field :total_price, value: @total %>
  <%= f.submit "注文を確定する" %>
<% end %>

後は注文履歴を表示する画面などで実際に表示できていれば成功です

おわりに

学習時に手伝っていただいたメンターの方、ありがとうございました。

実際に誰かに伝えるようにすることで、自分の書いたコードの無駄を発見できました。
今の私にはわかりませんが、ここに書いてあるコードにも実際には無駄が多くあるかも知れません。
もっともっと学習が必要だと思うきっかけになりました。

ここまでご覧下さりありがとうございました。

17
16
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
17
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?