schema.rb
:
create_table "cart_items", force: :cascade do |t|
t.integer "member_id", null: false #カート所有者(メンバー)ID(FK)
t.integer "item_id", null: false #商品詳細ページから引き渡すID(FK)
t.integer "quantity", null: false #カート内商品の数
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "items", force: :cascade do |t|
t.integer "genre_id", null: false #商品のジャンル
t.string "name", null: false #商品名
t.text "description", null: false #商品説明
t.string "image_id", null: false #商品写真
t.integer "price", null: false #商品値段
t.boolean "is_active", default: true, null: false #商品販売中
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
モデル設定
カート内商品(cart_item)と商品(item)を結びつける
1 : N = item : cart_item
```ruby:model/item.rb class Item < ApplicationRecord : has_many :cart_items : validates :price, presence: trueend
```ruby:model/cart_item.rb
class CartItem < ApplicationRecord
belongs_to :item
end
商品詳細ページで商品をカートに入れる
member/items.controller
class Member::ItemsController < ApplicationController
before_action :authenticate_member!, only: [:show]
:
#商品詳細ページ
def show
@item = Item.find(params[:id])
@cart_item =CartItem
end
private
def item_params
params.require(:items).permit(:genre_id,:name,:description,:image_id,:price)
end
end
form_withで情報を送る
f.hidden_field :item_id, :value => @item.idで文字だけでなくIDも引き渡す
item/show.html.erb
商品詳細ページでカートに入れるボタンを作りたい場面
<% if @item.is_active == TRUE %> #商品販売中の場合
<%= form_with(model: @cart_item,url: cart_items_path, method: :post,local: true)do |f| %>
<%= f.label :quantity, "個数選択" %>
<%= f.select :quantity, [1,2,3,4,5,6,7,8,9,10] %>
<%= f.hidden_field :item_id, :value => @item.id %>
#第一引数にオブジェクト名item_id、第二引数部分にvalueで受け渡す値 @item.idを指定
#cartitem controllerの cart_items.find_by(item_id:に送ることができる
<%= f.submit "カートに入れる" %>
<% end %>
<% end %>
カート内商品 一覧ページを作る
カートモデル(中間テーブル?)を使う方法もあるらしいが今回は使わない方法で記載
```ruby:cart_items.controller.rb class Member::CartItemsController < ApplicationController before_action :authenticate_member! def index @cart_items = current_member.cart_items.all end # カート商品を追加・保存 def create @cart_item = current_member.cart_items.new(cart_item_params) # もし元々カート内に「同じ商品」がある場合、「数量を追加」更新・保存する #ex.バナナ2個、バナナ2個ではなく バナナ「4個」にしたい if current_member.cart_items.find_by(item_id: params[:cart_item][:item_id]).present? #元々カート内にあるもの「item_id」 #今追加した params[:cart_item][:item_id]) cart_item = current_member.cart_items.find_by(item_id: params[:cart_item][:item_id]) cart_item.quantity += params[:cart_item][:quantity].to_i #cart_item.quantityに今追加したparams[:cart_item][:quantity]を加える #.to_iとして数字として扱う cart_item.save redirect_to cart_items_path # もしカート内に「同じ」商品がない場合は通常の保存処理
elsif @cart_item.save
@cart_items = current_member.cart_items.all
render 'index'
else # 保存できなかった場合
render 'index'
end
end
:
private
def cart_item_params
params.require(:cart_item).permit(:item_id, :price, :quantity)
end
end
<h2></h2>
<p></p>
```html:cart_item/index.html.erb
<h4>ショッピングカート</h4>
<table>
<tr>
<th>商品名</th>
<th>単価(税込)</th>
<th>数量</th>
<th>小計</th>
<th></th>
</tr>
<% total = 0 %> #合計金額totalの初期化
<% if current_member.cart_items.present? %> #カート内に商品があった場合
<% @cart_items.each do |cart_item| %>
<tr>
<td>
<%= attachment_image_tag(cart_item.item, :image, size: "60x50", fallback: "no_image.jpg") %> #商品画像
<%= cart_item.item.name %> #商品名
</td>
<td><%= (cart_item.item.price*1.08).to_i %></td> #商品単価(価格×1.08)
<td>
<%= form_with model: cart_item, url: cart_item_path(cart_item), local: true, method: :patch do |f| %>
<%= f.number_field :quantity, min: 1, max:10, id: "quantity_cart"%>
<%= f.submit "変更",class: "btn btn-success" %> #セレクトboxで数量変更
<% end %>
</td>
<td>
<% subtotal = ((cart_item.item.price*cart_item.quantity)*1.08).to_i %> #小計を計算する
<%= subtotal %> #小計を表示
</td>
<td>
<%= link_to "商品をカートから削除する", cart_item_path(cart_item.id, cart_item), method: :delete,class: "btn btn-danger" %>
</td>
</tr>
<% total += subtotal %> #アイテムごとに合計金額totalに反映 計算しておく
<% end %>
<% end %>
<tr>
<th>合計金額</th>
<td><%= total %></td>
</tr>
カートを空にする作業
orders_controller内でcart内の商品データを移す操作をあとでする
```routes.rb resources :cart_items,only: [:index,:create,:update,:destroy] do collection do delete "all_destroy" #パスが all_destroy_cart_items_path, method: :delete となる end end ``` ```ruby:cart_item.controller.rb def destroy cart_item = CartItem.find(params[:id]) cart_item.destroy @cart_items = CartItem.all render 'index' enddef all_destroy #カート内全て削除
cart_items = CartItem.all
cart_items.destroy_all
render 'index'
end
```html:cart_item/index.html.erb
:
<%= link_to "カートを空にする", all_destroy_cart_items_path, method: :delete,class: "btn btn-danger btn-sm" %>