LoginSignup
0
0

More than 1 year has passed since last update.

[Rails] テーブル間にテーブルを作成し設定する方法

Posted at

初めに

なぜこの記事を書きたかったのか 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)最後に

フリマアプリを使って言語化してみる!

asociatesample.png

[したいこと]ユーザが購入したものを履歴に残したい。

※商品の出品、商品一覧ページ、商品詳細ページを省く
[why]購入されたものをリストから除くように表示させることができるorユーザの購入傾向が分析できる
[need1]ユーザ、商品、注文、購入履歴のデータのテーブルが必要
[need2]各テーブルの情報を保存するためのシステムが必要
[need3]必要な情報のみを保存するようなシステムが必要
[need4]保存した情報を出力させたい場所を作る

[need1→how1]必要なテーブルの作成

USERS TABLE(個人の特定のため)
usertbsample.png
PRODUCTS TABLE(商品の登録のため)
producttbsample.png
ORDERS TABLE(注文するため)
ordertbsample.png
PURCHASE_HISTORIES TABLE(商品の有無のため)
purchase_historytbsample.png

[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の画像] 注文するときに,情報を制限して保存する機能を持つファイル
これで、クラス名を宣言すれば別のファイルにも使えるようになる
purchaseordermodel.png

[need3→how3]modelの設定

[user.rb画像] validationで保存するデータの制限+アソシエーション
usermodel.png

[product.rbの画像] validationで保存するデータの制限+アソシエーション(+画像の添付)
productmodel.png

[order.rbの画像] テーブル間のテーブル:perchase_historyとアソシエーションを組む
ordermodel.png

[perchase_history.rbの画像] 間にいるテーブルが結んでいるテーブルとアソシエーションを組む
purchasehistorymodel.png

[need4→how4]viewで置き場所の設定

[product/index.html.erbの画像] 商品の有無で表示方法を変える
okibashosample.png

[products_controller.rbの画像] orders_controllerで取得したデータをproducts_controllerで使用できるように設定
getparams2.png

最後

言語化してみてどこらへんが不安なところなのかも特定できてよかったと思う.

特定できた部分:
・なぜ間にテーブルを作成したのか。→多対多防止
・なぜactive_hashでもないのに別ファイルでモデルを作ったのか→注文時に必要なデータを制限したかった and 注文後の処理を設定したかったから
・アソシエーションが組まれていないのになぜ使えるのか→class名で機能を配置することができる

わかりにくいと感じましたら、ココ直したほうがいいよーなどのtipsをお願いします☺
ココまで読んでくださいましてありがとうございました!

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