自己学習メモ:エラー解決(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)
無事解決できたのは嬉しいけど、こんなミスをもう二度と経験したくないから、メモとして残しときます!!!