Token can't be blankと表示される(javascript)
Q&A
Closed
pay.jpを使用してフリマアプリの購入画面を実装しています。
order#createにてbinding.pryをすると以下のようにtokenがnilと表示され、購入ボタンを押しても、「Token can't be blank」と表示されます。
javascript内の記載が誤っていると予想して、色々と試しましたがわかりませんでした。
初歩的で申し訳ございませんが、ヒントをいただけると大変助かります。
そしてjavascript内の以下の記載もあっているのか不安です。
#のあとにindexに記載しているidを入力すると認識しているのですが、合っておりますでしょうか。
numberElement.mount('#card-number');
expiryElement.mount('#card-exp-month');
expiryElement.mount('#card-exp-year');
cvcElement.mount('#card-cvc');
エラーコード
[2] pry(#<OrdersController>)> order_params
Unpermitted parameters: :number, :exp_month, :exp_year, :cvc
=> <ActionController::Parameters {"postal_number"=>"520-0801", "prefecture_id"=>"2", "city"=>"あ", "address"=>"1", "building_name"=>"", "telephone_number"=>"09056401111", "user_id"=>12, "item_id"=>"12", "token"=>nil} permitted: true>
paramsと入力した場合のエラーでは、tokenの記載があります。
[1] pry(#<OrdersController>)> params
=> <ActionController::Parameters {"authenticity_token"=>"w03XQzQ8VpU+tQuew/LXNW2J1eNMrOTKgViG1UX9S+F8aIXuqL9mblO2AnaRXaARmUzI+r//m93udMNVi54KAw==", "order_payment"=>{"number"=>"12345678123456", "exp_month"=>"12", "exp_year"=>"24", "cvc"=>"234", "postal_number"=>"520-0801", "prefecture_id"=>"2", "city"=>"あ", "address"=>"1", "building_name"=>"", "telephone_number"=>"09056401111"}, "controller"=>"orders", "action"=>"create", "item_id"=>"12"} permitted: false>
コントローラー
class OrdersController < ApplicationController
before_action :authenticate_user!
def index
@item = Item.find(params[:item_id])
@order_payment = OrderPayment.new
end
def create
@item = Item.find(params[:item_id])
binding.pry
@order_payment = OrderPayment.new(order_params)
if @order_payment.valid?
pay_item
@order_payment.save
return redirect_to root_path
else
render :index
end
end
private
def order_params
params.require(:order_payment).permit(:postal_number, :prefecture_id, :city, :address, :building_name, :telephone_number).merge(user_id: current_user.id, item_id: params[:item_id],token: params[:token])
end
def pay_item
Payjp.api_key = ENV["PAYJP_SECRET_KEY"]
Payjp::Charge.create(
amount: @item.price, # 商品の値段
card: order_params[:token], # カードトークン
currency: 'jpy' # 通貨の種類(日本円)
)
end
javascript(card.js)
const pay = () => {
const payjp = Payjp(process.env.PAYJP_PUBLIC_KEY)
const elements = payjp.elements();
const numberElement = elements.create('cardNumber');
const expiryElement = elements.create('cardExpiry');
const cvcElement = elements.create('cardCvc');
numberElement.mount('#card-number');
expiryElement.mount('#card-exp-month');
expiryElement.mount('#card-exp-year');
cvcElement.mount('#card-cvc');
const submit = document.getElementById("button");
submit.addEventListener("click", (e) => {
e.preventDefault();
payjp.createToken(numberElement).then(function (response) {
if (response.error) {
} else {
const token = response.id;
const renderDom = document.getElementById("charge-form");
const tokenObj = `<input value=${token} type="hidden" name='token'>`;
renderDom.insertAdjacentHTML("beforeend", tokenObj);
}
numberElement.clear();
expiryElement.clear();
cvcElement.clear();
document.getElementById("charge-form").submit();
});
});
};
window.addEventListener("load", pay);
index.html
<%= render "shared/second-header"%>
<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.item_name %>
</h2>
<div class='buy-item-price'>
<p class='item-price-text'>¥<%= @item.price %></p>
<p class='item-price-sub-text'><%= @item.delivery_charge.delivery_charge %></p>
</div>
</div>
</div>
<%# /購入内容の表示 %>
<%# 支払額の表示 %>
<div class='item-payment'>
<h1 class='item-payment-title'>
支払金額
</h1>
<p class='item-payment-price'>
¥<%= @item.price %>
</p>
</div>
<%# /支払額の表示 %>
<%= form_with(model: @order_payment, url: item_orders_path(@item), id: 'charge-form', class: 'transaction-form-wrap',local: true ) do |f| %>
<%= render 'shared/error_messages', model: f.object %>
<%# カード情報の入力 %>
<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 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 :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='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_number, 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 :address, 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 :telephone_number, class:"input-default", id:"phone-number", placeholder:"例)09012345678",maxlength:"11"%>
</div>
</div>
<%# /配送先の入力 %>
<div class='buy-btn'>
<%= f.submit "購入" ,class:"buy-red-btn", id:"button" %>
</div>
<% end %>
</div>
</div>
<%= render "shared/second-footer"%>
バリデーション
class OrderPayment
include ActiveModel::Model
attr_accessor :postal_number, :prefecture_id, :city, :address, :building_name, :telephone_number, :user_id, :item_id, :token
#バリデーションを記載する
with_options presence: true do
validates :user_id
validates :item_id
validates :postal_number, format: {with: /\A[0-9]{3}-[0-9]{4}\z/, message: "is invalid. Include hyphen(-)"}
validates :prefecture_id, numericality: { other_than: 1, message: "can't be blank" }
validates :city
validates :address
validates :telephone_number, format: {with: /\A[0-9]{11}\z/, message: 'is invalid' }
validates :token
end
#データをテーブルに保存する処理
def save
# 発送先情報を保存し、変数orderに代入する
order = Order.create(item_id: item_id, user_id: user_id)
# 住所を保存する
# order_idには、変数orderのidと指定する
Payment.create(postal_number: postal_number, prefecture_id: prefecture_id, city: city, address: address, building_name: building_name, telephone_number: telephone_number, order_id: order.id)
end
end
テーブル
class CreatePayments < ActiveRecord::Migration[6.0]
def change
create_table :payments do |t|
t.string :postal_number, null: false
t.integer :prefecture_id, null: false
t.string :city, null: false
t.string :address, null: false
t.string :building_name
t.string :telephone_number, null: false
t.references :order, null: false, foreign_key:true
t.timestamps
end
end
end
1