以前住所を入力したので、このようにまだ何も入力してませんが、すでに値が入っています
今回は、ユーザーが住所を入力して商品を購入した時に、次からは、その住所を使い回す的な機能を実装していきます
従来の問題
今までは、ユーザーの情報と、住所の情報が紐付いてなくて、商品を購入するたびに、いちいち住所を入力しなければならず、使い勝手が悪いアプリでした。
ユーザーと住所を紐付ける
何はともあれ、このような機能を実装するには、ユーザーと住所を紐付けないといけないので、紐付けていきます
住所の情報が入ったaddressesテーブルです。
ここにuser_idとかいう外部キーを入れて、ユーザーと住所を紐付けたりします。
外部キーのカラムの追加の仕方は今回は割愛。
ググったら出てきます
アソシエーションを組む
user.rb
has_one: address
address.rb
belongs_to: user
ユーザーが親ですね。住所っていうのはユーザーあってのものなので(説明が適当すぎてすいません)
一つのビューで複数のテーブルに値を保存する処理を書く
trades_controller.rb
def index
# 購入ページ
@item = Drink.find(params[:drink_id])
@order = TradeAddress.new
@user_address = current_user.address
end
def new
@item = Drink.find(params[:drink_id])
@order = TradeAddress.new
# 商品購入ページ
end
def create
@item = Drink.find(params[:drink_id])
@order = TradeAddress.new(trade_params)
if @order.valid?
pay_item
@order.save
else
render 'index'
end
end
trade_address.rb
class TradeAddress
include ActiveModel::Model
include ActiveRecord::AttributeAssignment
include SessionsHelper
# form_withやrender等の色々な機能が使える
attr_accessor :fam_name,:first_name,:fam_name_kana,:first_name_kana,:birthday,:postal_code, :city, :house_num, :building_name, :phone_num, :drink_id, :prefecture_id,:trade_id, :user_id, :price,:token,:authenticity_token,:number,:exp_month,:exp_year,:cvc,:commit
with_options presence: true do
with_options format: { with: /\A[ぁ-んァ-ン一-龥]/, message: 'は全角で入力してください。' } do
validates :fam_name
validates :first_name
end
with_options format: { with: /\A[ァ-ヶー-]+\z/, message: 'は全角カタカナで入力して下さい。' } do
validates :fam_name_kana
validates :first_name_kana
end
validates :birthday
validates :postal_code,format: {with: /\A\d{3}[-]\d{4}\z/}
validates :prefecture_id, numericality: { other_than: 1 }
validates :city
validates :house_num
validates :phone_num
validates :token
end
def save
trade = Trade.create(user_id: user_id, drink_id: drink_id)
Address.create(fam_name: fam_name,first_name: first_name,fam_name_kana: fam_name_kana,first_name_kana: first_name_kana,postal_code: postal_code, prefecture_id: prefecture_id, birthday: birthday,city: city, house_num: house_num, building_name: building_name, phone_num: phone_num, trade_id: trade.id,user_id: user_id)
end
end
複数テーブルに値を保存するFormsヘルパーの使い方についても割愛
trades/index.html.erb
かなり冗長なコードですが、
@user_addressがあったら、value: @user_address.first_nameみたいに、
初期値をセットすると言ったやり方です
フォームとかにvalue: hoge
とかやったりすると、そのフォームにすでにhogeと入力されてる状態となっております
ちなみに、select系のフォームは
selectedとかで初期値をセットしてます。
下に具体的なコードを書いてるのでぜひ見てください
ってか、馬鹿みたいに冗長ですね。
form_withがそこら辺をよしなにやって欲しかったのですが、何ともできなかった。。。。
<% if @user_address%>
<div class='transaction-contents'>
<div class='transaction-main'>
<h1 class='transaction-title-text'>
購入内容の確認
</h1>
<%# 購入内容の表示 %>
<div class='buy-item-info'>
<%= image_tag @item.image, class: 'buy-item-img' %>
<div class='buy-item-right-content'>
<h2 class='buy-item-text'>
<%= @item.name %>
</h2>
<div class='buy-item-price'>
<p class='item-price-text'>¥<%= @item.price %></p>
<p class='item-price-sub-text'>(税込)送料込み</p>
</div>
</div>
</div>
<%# /購入内容の表示 %>
<%# 支払額の表示 %>
<div class='item-payment'>
<h1 class='item-payment-title'>
支払金額
</h1>
<p class='item-payment-price'>
¥<%= @item.price %>円
</p>
</div>
<%# /支払額の表示 %>
<%= render 'shared/error_messages', object: @order %>
<%= form_with id: 'charge-form', class: 'transaction-form-wrap',local: true do |f| %>
<%# カード情報の入力 %>
<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 :number, class:"input-default", id:"card-number", placeholder:"カード番号(半角英数字)", maxlength:"16" %>
</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 :exp_month, class:"input-expiration-date", id:"card-exp-month", placeholder:"例)3" %>
<p>月</p>
<%= f.text_area :exp_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 :cvc,class:"input-default", id:"card-cvc", placeholder:"カード背面4桁もしくは3桁の番号", maxlength:"4" %>
</div>
</div>
<%# /カード情報の入力 %>
<%# 配送先の入力 %>
<div class="user-address">
<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 :fam_name, class:"input-default", id:"postal-code",placeholder:"例) 原",value: @user_address.fam_name %>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">名前</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :first_name, class:"input-default", id:"postal-code" ,placeholder:"例) 奏一郎",value: @user_address.first_name %>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">苗字カナ</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :fam_name_kana, class:"input-default", id:"postal-code" ,placeholder:"例) ハラ",value: @user_address.fam_name_kana %>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">名前カナ</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :first_name_kana, class:"input-default", id:"postal-code",placeholder:"例) ソウイチロウ",value: @user_address.first_name_kana %>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">生年月日</label>
<span class="indispensable">必須</span>
</div>
<%= raw sprintf(
f.date_select(
:birthday,
class:'select-box',
id:"birth-date",
use_month_numbers: true,
prompt:'--',
start_year: 1945,
selected: @user_address.birthday ,
end_year: (Time.now.year - 5),
date_separator: '%s'),
"<p> 年 </p>", "<p> 月 </p>") + "<p> 日 </p>" %>
</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 :postal_code, class:"input-default", id:"postal-code", placeholder:"例)123-4567(ハイフンを含めてください)", maxlength:"8" ,value: @user_address.postal_code %>
</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,{selected: @user_address.prefecture_id }, {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 :city, class:"input-default", id:"city", placeholder:"例)武蔵村山市星野区",value: @user_address.city %>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">番地</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :house_num, class:"input-default", id:"addresses", placeholder:"例)神明1-1-1",value: @user_address.house_num %>
</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:"例)立川ビル801",value: @user_address.building_name %>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">電話番号</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :phone_num, class:"input-default", id:"phone-number", placeholder:"例)09012345678",maxlength:"11",value: @user_address.phone_num %>
</div>
</div>
<%# /配送先の入力 %>
<div class='buy-btn'>
<%= f.submit "購入" ,class:"buy-red-btn",id: "buy-red-btn" %>
</div>
<% end %>
</div>
</div>
<% else %>
<div class='transaction-contents'>
<div class='transaction-main'>
<h1 class='transaction-title-text'>
購入内容の確認
</h1>
<%# 購入内容の表示 %>
<div class='buy-item-info'>
<%= image_tag @item.image, class: 'buy-item-img' %>
<div class='buy-item-right-content'>
<h2 class='buy-item-text'>
<%= @item.name %>
</h2>
<div class='buy-item-price'>
<p class='item-price-text'>¥<%= @item.price %></p>
<p class='item-price-sub-text'>(税込)送料込み</p>
</div>
</div>
</div>
<%# /購入内容の表示 %>
<%# 支払額の表示 %>
<div class='item-payment'>
<h1 class='item-payment-title'>
支払金額
</h1>
<p class='item-payment-price'>
¥<%= @item.price %>円
</p>
</div>
<%# /支払額の表示 %>
<%= render 'shared/error_messages', object: @order %>
<%= form_with id: 'charge-form', class: 'transaction-form-wrap',local: true do |f| %>
<%# カード情報の入力 %>
<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 :number, class:"input-default", id:"card-number", placeholder:"カード番号(半角英数字)", maxlength:"16" %>
</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 :exp_month, class:"input-expiration-date", id:"card-exp-month", placeholder:"例)3" %>
<p>月</p>
<%= f.text_area :exp_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 :cvc,class:"input-default", id:"card-cvc", placeholder:"カード背面4桁もしくは3桁の番号", maxlength:"4" %>
</div>
</div>
<%# /カード情報の入力 %>
<%# 配送先の入力 %>
<div class="user-address">
<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 :fam_name, class:"input-default", id:"postal-code",placeholder:"例) 原"%>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">名前</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :first_name, class:"input-default", id:"postal-code" ,placeholder:"例) 奏一郎"%>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">苗字カナ</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :fam_name_kana, class:"input-default", id:"postal-code" ,placeholder:"例) ハラ"%>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">名前カナ</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :first_name_kana, class:"input-default", id:"postal-code",placeholder:"例) ソウイチロウ"%>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">生年月日</label>
<span class="indispensable">必須</span>
</div>
<%= raw sprintf(
f.date_select(
:birthday,
class:'select-box',
id:"birth-date",
use_month_numbers: true,
prompt:'--',
start_year: 1945,
end_year: (Time.now.year - 5),
date_separator: '%s'),
"<p> 年 </p>", "<p> 月 </p>") + "<p> 日 </p>" %>
</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 :postal_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 :city, 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 :house_num, 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:"例)立川ビル801"%>
</div>
<div class="form-group">
<div class='form-text-wrap'>
<label class="form-text">電話番号</label>
<span class="indispensable">必須</span>
</div>
<%= f.text_field :phone_num, class:"input-default", id:"phone-number", placeholder:"例)09012345678",maxlength:"11"%>
</div>
</div>
<%# /配送先の入力 %>
<div class='buy-btn'>
<%= f.submit "購入" ,class:"buy-red-btn",id: "buy-red-btn" %>
</div>
<% end %>
</div>
</div>
<% end %>