質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.37%

Payjp カード情報登録時のエラー

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 2,420

score 5

問題点

Payjpを導入し、ユーザー登録と同時にカード情報登録をしたい。
しかし、カード情報登録時に"card_id: customer.default_card"の値がnullで返って来てしまう

開発環境

ruby '2.5.1'
rails '5.2.4'
gem 'jquery-rails'
gem 'payjp'

詳細

JSの記入は出来ており、トークンの発行も出来ています。
また、下記コードにおいて、@card以下の"user_id: current_user.id","customer_id: customer.id"の情報は取得できています。
payjp側では顧客一覧のなかに登録はされているが、カード情報の欄が"カード未登録"となっています。

*ウイザードを使って、ユーザー登録をしています。それと同時にカード情報の登録をしたいので、createが長くなっています。

<--signup controller-->
  def create
    @user = User.new(
      nickname: session[:nickname],
      email: session[:email],
      password: session[:password],
      last_name: session[:last_name], 
      first_name: session[:first_name], 
      last_name_kana: session[:last_name_kana], 
      first_name_kana: session[:first_name_kana], 
      phone_number: session[:phone_number], 
      birthday: session[:birthday] ,
    )

    @user.build_address(
      zip_code: session[:zip_code],
      prefecture_id: session[:prefecture_id],
      city: session[:city],
      block: session[:block], 
      building: session[:building],
    )


    if @user.save
      session[:id] = @user.id
      sign_in User.find(session[:id]) unless user_signed_in?
    else
      render '/signup/step1'
    end
    Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
    if params['payjp_token'].blank?
      render '/signup/step4'
    else
      customer = Payjp::Customer.create(
        description: 'test',
        email: current_user.email,
        card: params['payjp-token'],
        metadata: {user_id: current_user.id}
      )
      @card = Card.new(
        user_id: current_user.id, 
        customer_id: customer.id,
        card_id: customer.default_card
      )
      if @card.save
        redirect_to done_signup_index_path
      else
        redirect_to action: "create"
      end
    end
  end
document.addEventListener(
  "DOMContentLoaded", e =>{
    if (document.getElementById("token_submit") != null) {
      Payjp.setPublicKey("pk_test_xxxxxxxxxxxxxxxxxxxxxxxx");
      let btn = document.getElementById("token_submit"); 
      btn.addEventListener("click", e => { 
        e.preventDefault();
        let card = {
          number: document.getElementById("card_number").value,
          cvc: document.getElementById("cvc").value,
          exp_month: document.getElementById("exp_month").value,
          exp_year: document.getElementById("exp_year").value,
        }; 
        Payjp.createToken(card, (status, response) => {
          if (status === 200){
            $("#card_nummber").removeAttr("name");
            $("#cvc").removeAttr("name");
            $("#exp_month").removeAttr("name");
            $("#exp_year").removeAttr("name");
            var token = response.id;
            $("#charge-form").append($('<input type="hidden" name="payjp_token" class="payjp-token" />').val(token));
            $("#charge-form").get(0).submit();
          }else{
            alert("Error");
          }
        });
      });
    }
  },
  false
);
<----- 登録画面 ----->
.session_wrapper
  .signup__header
    %h1.signup__header__logo
    = link_to image_tag("/fmarket_logo_red.svg", size: "185x49"), root_path
    %nav#nav.progress-bar.signup__header__bar
      %ol
        %li
          会員情報
          .progress-status__first.active.let_active
        %li
          電話番号認証
          .progress-status.active.let_active
        %li
          お届け先住所入力
          .progress-status.active.let_active
        %li.active
          支払い方法
          .progress-status.active
        %li
          完了
          .progress-status__last
  .session_wrapper
    .single_container
      .session__main
        .session__main__container
          %h2.session__main__container__title 支払い方法
          = form_with url: signup_index_path, name: "form", id: 'charge-form', method: :post, html:{class: 'session__main__container__box'} do |f|
            .session__main__container__formGroup
              %label{for: "nickname"}
                カード番号
                %span.form__require 必須
              = f.text_field "number", class: "input__default", placeholder: "半角数字のみ", type: "text", id: "card_number", maxlength: "16"
              .session__main__container__formGroup__sub
                %i.fab.fa-cc-visa
                %i.fab.fa-cc-mastercard
                %i.fab.fa-cc-jcb
                %i.fab.fa-cc-discover
                %i.fab.fa-cc-amex
                / ↑画像使うと容量圧迫するのでアイコンで仮置き
            .session__main__container__formGroup
              %label{for: "nickname"}
                有効期限
                %span.form__require 必須
              .session__main__container__formGroup__sub
                %select.select__wap#exp_month{name: "exp_month", type: "text"}
                  %option{value: ""} --
                  %option{value: "01"} 01
                  %option{value: "02"} 02
                  %option{value: "03"} 03
                  %option{value: "04"} 04
                  %option{value: "05"} 05
                  %option{value: "06"} 06
                  %option{value: "07"} 07
                  %option{value: "08"} 08
                  %option{value: "09"} 09
                  %option{value: "10"} 10
                  %option{value: "11"} 11
                  %option{value: "12"} 12
                %i.fas.fa-chevron-down.select_arrow
                %p                %select.select__wap#exp_year{name: "exp_year", type: "text"}
                  %option{value: ""} --
                  %option{value: "2019"} 19
                  %option{value: "2020"} 20
                  %option{value: "2021"} 21
                  %option{value: "2022"} 22
                  %option{value: "2023"} 23
                  %option{value: "2024"} 24
                  %option{value: "2025"} 25
                %i.fas.fa-chevron-down.select_arrow
                %p 年
              .session__main__container__formGroup
                %label{for: "nickname"}
                  セキュリティーコード
                  %span.form__require 必須
                = f.text_field "cvc", class: "input__default cvc", placeholder: "カード背面4桁もしくは3桁の番号", type: "text"
                .session__main__container__formGroup__link
                  = link_to root_path do
                    %i.fas.fa-question-circle
                    %p セキュリティーコードとは
                .session__main__container__formGroup#card_token
                  = f.submit "次へ進む", class: "btn_default btn_mail", id: "token_submit"
<---- migrationfile ---->
class CreateCards < ActiveRecord::Migration[5.2]
  def change
    create_table :cards do |t|
      t.references :user, null: false, foreign_key:true
      t.string :customer_id, null: false
      t.string :card_id, null: true
      t.timestamps
    end
  end
end
<---- model ---->
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :omniauthable, omniauth_providers: [:google, :facebook]

   --- userのバリデーション省略 ---
has_one :card, dependent: :destroy

-------------------------------------------

class Card < ApplicationRecord
  belongs_to :user
end
console.log(card)

Objectcvc: 
"123"exp_month: 
"12"exp_year: 
"2020"number: 
"4242424242424242"__proto__: 
Object

console.log(response)

Object
card:
address_city: null
address_line1: null
address_line2: null
address_state: null
address_zip: null
address_zip_check: "unchecked"
brand: "Visa"
country: null
created: 1576383087
customer: null
cvc_check: "passed"
exp_month: 12
exp_year: 2020
fingerprint: "e1d8225886e3a7211127df751c86787f"
id: "car_214e1ffe515c6a313fe0db10bb70"
last4: "4242"
livemode: false
metadata: {}
name: null
object: "card"
__proto__: Object
created: 1576383087
id: "tok_d4ef9c9f0c2ef2991812f9860c60"
livemode: false
object: "token"
used: false
__proto__: Object

試したこと

色々なサイトを見て見ましたが、登録時のcontrollerの記述はほとんど変わらずでした。
t.string :card_id, null: trueは初めはnull: falseでしたが、弾かれるので変更しました。
商品購入時に登録してしまえ、と思いましたが、うまくいかず、根本的な解決が必要だと考えました。
ご教示いただけたらと存じます。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

原因

controller内
customer以下の記述ミス

誤
card: params['payjp-token'],
正
card: params['payjp_token'],


name属性から取ってこないといけないところ、class指定になっていました

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る