初めに
なぜこの記事を書きたかったのか or この記事の対象者
テーブルとテーブルの間のテーブルの設定と仕組みが未だに自信ないから一度言語化させたかった。
特に理解が追いつけないのが、テーブル間のテーブルの設定になぜ別のモデルを作成しなければならないのか。
環境
・Macbook Air (Retina, 13-inch,2019)
・プロセッサ 1.6GHz デュアルコアIntel Core i5
・メモリ 8GB 2133 Mhz LPDDR3
・MacOS Big Sur バージョン 11.5.2
記事の目次
1)フリマアプリを使って言語化してみる!
2)[したいこと]
3)[need1→how1]必要なテーブルの作成
4)[need2→how2]viewで記入欄の作成,controllerで各アクションの設定
5)[need3→how3]modelの設定
6)[need4→how4]viewで置き場所の設定
7)最後に
フリマアプリを使って言語化してみる!
[したいこと]ユーザが購入したものを履歴に残したい。
※商品の出品、商品一覧ページ、商品詳細ページを省く
[why]購入されたものをリストから除くように表示させることができるorユーザの購入傾向が分析できる
[need1]ユーザ、商品、注文、購入履歴のデータのテーブルが必要
[need2]各テーブルの情報を保存するためのシステムが必要
[need3]必要な情報のみを保存するようなシステムが必要
[need4]保存した情報を出力させたい場所を作る
[need1→how1]必要なテーブルの作成
USERS TABLE(個人の特定のため)
PRODUCTS TABLE(商品の登録のため)
ORDERS TABLE(注文するため)
PURCHASE_HISTORIES TABLE(商品の有無のため)
[need2→how2]viewで記入欄の作成,controllerで各アクションの設定
商品の購入ができる画面
<div class='transaction-contents'>
<div class='transaction-main'>
<h1 class='transaction-title-text'>
購入内容の確認
</h1>
<div class='buy-item-info'>
<% @product.images.each do |image| %>
<%= image_tag image, class: 'images'%>
<% end %>
<div class='buy-item-right-content'>
<h2 class='buy-item-text'>
<%= @product.name %>
</h2>
<div class='buy-item-price'>
<p class='item-price-text'>¥<%= @product.price %></p>
<p class='item-price-sub-text'><%= @product.shipping_charges.name %></p>
</div>
</div>
</div>
<div class='item-payment'>
<h1 class='item-payment-title'>
支払金額
</h1>
<p class='item-payment-price'>
¥<%= @product.price %>
</p>
</div>
<%= form_with model: @perchase_order ,url: product_orders_path, id: 'charge-form', class: 'transaction-form-wrap',local: true do |f| %>
<%= render 'shared/error_messages', model:@perchase_order %>
<div class='credit-card-form'>
<h1 class='info-input-haedline'>
クレジットカード情報入力
</h1>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">カード情報</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :credit_number, class:"input-default",id:"card-number", placeholder:"カード番号(半角英数字)", maxlength:"16" %>
<div class='available-card'>
<%= image_tag 'card-visa.gif', class: 'card-logo'%>
<%= image_tag 'card-mastercard.gif', class: 'card-logo'%>
<%= image_tag 'card-jcb.gif', class: 'card-logo'%>
<%= image_tag 'card-amex.gif', class: 'card-logo'%>
</div>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">有効期限</label>
<span class="indispensable">必須</span>
</div>
<div class='input-expiration-date-wrap'>
<%= f.text_area :expire_month, class:"input-expiration-date",id:"card-exp-month", placeholder:"例)3" %>
<p>月</p>
<%= f.text_area :expire_year, class:"input-expiration-date",id:"card-exp-year", placeholder:"例)23" %>
<p>年</p>
</div>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">セキュリティコード</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :security_code,class:"input-default",id:"card-cvc", placeholder:"カード背面4桁もしくは3桁の番号", maxlength:"4" %>
</div>
</div>
<div class='shipping-address-form'>
<h1 class='info-input-haedline'>
配送先入力
</h1>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">郵便番号</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :zip_code, class:"input-default", id:"postal-code", placeholder:"例)123-4567", maxlength:"8" %>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">都道府県</label>
<span class="indispensable">必須</span>
</div>
<%= f.collection_select(:prefecture_id, Prefecture.all, :id, :name, {}, {class:"select-box", id:"prefecture"}) %>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">市区町村</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :municipality, class:"input-default", id:"city", placeholder:"例)横浜市緑区"%>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">番地</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :adress, class:"input-default", id:"addresses", placeholder:"例)青山1-1-1"%>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">建物名</label>
<span class="form-any">任意</span>
</div>
<%= f.text_field :building_name, class:"input-default", id:"building", placeholder:"例)柳ビル103"%>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">電話番号</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :phone_number, class:"input-default", id:"phone-number", placeholder:"例)09012345678",maxlength:"11"%>
</div>
</div>
<div class='buy-btn'>
<%= f.submit "購入" ,class:"buy-red-btn" %>
</div>
<% end %>
</div>
</div>
商品購入画面のアクション設定
class OrdersController < ApplicationController
before_action :authenticate_user!, only: [:index, :create]
before_action :move_to_index, only: [:index, :create]
before_action :payed_redirect, only: [:index, :create]
def index
@perchase_order = PerchaseOrder.new
end
def create
@perchase_order = PerchaseOrder.new(order_params)
if @perchase_order.valid?
paying
@perchase_order.save
redirect_to root_path
else
render :index
end
end
private
def order_params
params.require(:perchase_order).permit(:zip_code, :prefecture_id, :municipality, :adress, :building_name,
:phone_number).merge(user_id: current_user.id, token: params[:token], product_id: params[:product_id])
end
def paying
Payjp.api_key = ENV['PAYJP_SECRET_KEY']
Payjp::Charge.create(
amount: @product.price,
card: order_params[:token],
currency: 'jpy'
)
end
def move_to_index
@product = Product.find(params[:product_id])
redirect_to '/' if @product.user.id == current_user.id
end
def payed_redirect
redirect_to '/' unless @product.purchase_history.nil?
end
end
ファイルに名前をつけて、機能を追加する記述方法↓
class モデル名
機能,設定、ルール
end
他のテーブル/モデルからカラムの取得する記述方法↓
include ActiveModel::Model
altr_accessor :カラム名, :カラム名, :カラム名
[perchase_order.rbの画像] 注文するときに,情報を制限して保存する機能を持つファイル
これで、クラス名を宣言すれば別のファイルにも使えるようになる
[need3→how3]modelの設定
[user.rb画像] validationで保存するデータの制限+アソシエーション
[product.rbの画像] validationで保存するデータの制限+アソシエーション(+画像の添付)
[order.rbの画像] テーブル間のテーブル:perchase_historyとアソシエーションを組む
[perchase_history.rbの画像] 間にいるテーブルが結んでいるテーブルとアソシエーションを組む
[need4→how4]viewで置き場所の設定
[product/index.html.erbの画像] 商品の有無で表示方法を変える
[products_controller.rbの画像] orders_controllerで取得したデータをproducts_controllerで使用できるように設定
最後
言語化してみてどこらへんが不安なところなのかも特定できてよかったと思う.
特定できた部分:
・なぜ間にテーブルを作成したのか。→多対多防止
・なぜactive_hashでもないのに別ファイルでモデルを作ったのか→注文時に必要なデータを制限したかった and 注文後の処理を設定したかったから
・アソシエーションが組まれていないのになぜ使えるのか→class名で機能を配置することができる
わかりにくいと感じましたら、ココ直したほうがいいよーなどのtipsをお願いします☺
ココまで読んでくださいましてありがとうございました!