自己学習メモ:エラー解決(undefined local variable or method `purchase' for #<PurchaseAddress:0x00007ffd49e9b670>)

自己検証の内容:

エラー画面

 スクリーンショットを貼る

undefined local variable or method `purchase' for #<PurchaseAddress:0x00007ffd49e9b670>

解決したいこと

  • formオブジェクトパタンを用いた購入機能を実装中。
  • form_withで入力したデータはdbに保存したいが、purchaseテーブルへの保存ができたが、address テーブルへの保存ができなかったこと

調べた内容とそこから立てた仮説

 カリキュラムの donation appを参考に購入機能を実装してみた コントローラでpurchase_addressのインスタンスを生成し、form_with に代入ができたと思いますが、form_wiht で入力したデータをコントローラで送ってきた値をバリデーションをかけ、エラーメッセージも出ていて、purchase_address.rbでsaveできないのは今回の問題点かと思いますが、カリキュラムと同じ設定方法で記述したため、問題は別のところにあるのではと考えております。

 

仮説を元に行った作業内容

 (例)コントローラーにbinding.pryを設け処理をとめた。  何が受け取れているのかを確認したところ、トークンの受け取りは確認できなかった。  JSからパラメーターが送られていないのか確認しようとしたが、適切に確認できているのか  分からなかった。

新たにmodelsディレクトリ直下にファイルを作成し、クラスを定義した(formオブジェクトパタンを実行)

class PurchaseAddress
  include ActiveModel::Model
  attr_accessor :user_id, :item_id, :postal_code, :city, :house_number, :phone_number, :building_name, :prefecture_id

  with_options presence: true do
    validates :postal_code, 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 :house_number
    validates :phone_number, format: { with: /\A0[0-9]+\z/, message: 'number is invalid. Include half-width numbers' } 
    validates :user_id
    validates :item_id
  end

  def save
    Purchase.create(user_id: user_id, item_id: item_id)
    Address.create(postal_code: postal_code, city: city, house_number: house_number, phone_number: phone_number, building_name: building_name, prefecture_id: prefecture_id, purchase_id: purchase.id)

    # item = Item.find(params[:item_id])
    # @purchase = item.create_purchase!(user_id: current_user.id)
    # @purchase.create_address!(address_params)
    # redirect_to root_path
  end

end

purchaseコントローラ

class PurchasesController < ApplicationController
  before_action :authenticate_user!, except: :index
  def index
    @item = Item.find(params[:item_id])
    @purchase_address = PurchaseAddress.new
    # @purchase_address = @item.build_purchase_address
  end

  def new
    @purchase_address = PurchaseAddress.new
    # @purchase_address = @item.build_purchase_address

  end
  
  def create
    @item = Item.find(params[:item_id])
    @purchase_address = PurchaseAddress.new(purchase_params)
    # @purchase_address = item.build_purchase_address(purchase_params)
    if @purchase_address.valid?
       @purchase_address.save
       redirect_to root_path
    else
      render :index
    end
  #   item = Item.find(params[:item_id])
  #   @purchase = item.create_purchase!(user_id: current_user.id)
  #   @purchase.create_address!(address_params)
  #   redirect_to root_path
  end

  private

  # def purchase_params 
  #   params.merge(user_id: current_user.id, item_id: params[:item_id])
  # end 

  # def address_params
    # params.permit(:postal_code, :prefecture_id, :city, :house_number, :phone_number, :building_name).merge(purchase_id: @purchase.id)  
  # end
  def purchase_params
    params.permit(:postal_code, :prefecture_id, :city, :house_number, :phone_number, :building_name).merge(user_id: current_user.id, item_id: params[:item_id])
  end
end

フォームのmodelオプションを設定したコード:現段階では、pay.jpを導入していないため、カード情報の入力をコメントアウトしている

<%= render "shared/second-header"%>
<%= form_with url: item_purchases_path, method: @purchase_address, local: true do |f| %>
<%= render 'shared/error_messages', model: @purchase_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'><%= @item.shipping.shipping_id %></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 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 :hoge, 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 :hoge, class:"input-expiration-date", id:"card-exp-month", placeholder:"例)3" %> %>
          <%# <p>月</p> %>
          <%# <%= f.text_area :hoge, 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 :hoge, 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_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, :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:"例)横浜市緑区"%>
      </div>
      <div class="form-group">
        <div class='form-text-wrap'>
          <label class="form-text">番地</label>
          <span class="indispensable">必須</span>
        </div>
        <%= f.text_field :house_number, 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", id:"button" %>
    </div>
    <%# <% end %> %>
  </div>
</div>
<% end %>
<%= render "shared/second-footer"%>

もう一回 やり直してみたら、やっぱり問題点はここでした!!!

  def save
    purchase = Purchase.create(user_id: user_id, item_id: item_id)   # 変数purchase に代入しなかったため
    Address.create(postal_code: postal_code, city: city, house_number: house_number, phone_number: phone_number, building_name: building_name, prefecture_id: prefecture_id, purchase_id: purchase.id)

無事解決できたのは嬉しいけど、こんなミスをもう二度と経験したくないから、メモとして残しときます!!!