1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails】furimaアプリ 商品購入機能 #1

Posted at

実装概要

商品をクレジットカード決済で購入する機能を実装から単体テストまで行う

事前準備 Turbo機能をオフにする

views/items/show.html.erb
# 中略

~data: { turbo: false }~%>

# 中略

PAY.JPを使用するためには、Turboの機能をオフにする必要があるため上記コードを追記

Purchasesコントローラーの作成

ターミナル

% rails g controller purchases

indexアクションの定義

app/controllers/purchases_controller.rb
def index
end

ルーティングの設定

config/routes.rb
# 中略
resources :purchases, only: :index

購入、送付先住所についてのモデルとテーブルの作成

ターミナル

% rails g model purchese
% rails g model shipping_address

マイグレーションファイルを編集

db/migrate/2024******_create_purchases.rb
class CreatePurchases < ActiveRecord::Migration[7.0]
  def change
    create_table :purchases do |t|
      t.references    :user, null: false, foreign_key: true
      t.references    :item, null: false, foreign_key: true
      t.timestamps
    end
  end
end
db/migrate/2024*****_create_shipping_addresses.rb
class CreateShippingAddresses < ActiveRecord::Migration[7.0]
  def change
    create_table :shipping_addresses do |t|
      t.string      :postal_code, null: false
      t.integer     :prefecture_id, null: false
      t.string      :city, null: false
      t.string      :address, null: false
      t.string      :building_name
      t.string      :phone_number, null: false
      t.references  :purchase, null: false, foreign_key: true

      t.timestamps
    end
  end
end

マイグレーションファイルを実行
ターミナル

% rails db:migrate

アソシエーションの追加

app/models/user.rb
# 中略
has_many :purchases
app/models/item.rb
# 中略
has_one :purchase
app/models/purchase.rb
belongs_to :user
belongs_to :item
has_one :shipping_address
app/models/shipping_address.rb
belongs_to :purchase

Formオブジェクトの作成

modelsディレクトリ直下にpurchase_form.rbファイルを作成
併せてバリデーションも設定

app/models/purchase_form.rb
include ActiveModel::Model
attr_accessor :user_id, :item_id, :postal_code, :prefecture_id, :city, :address, :building_name, :phone_number
with_options presence: true do
    validates :user_id
    validates :item_id
    validates :postal_code, format: { with: /\A[0-9]{3}-[0-9]{4}\z/, message: 'is invalid. Include hyphen(-)' }
    validates :city
    validates :address
    validates :phone_number, format: { with: /\A[0-9]{10,11}\z/, message: 'must be 10 or 11 digits long' }
  end
  validates :prefecture_id, numericality: { other_than: 0, message: "can't be blank" }

attr_accessorは、インスタンス変数の読み書き用メソッドを自動生成し、コードをシンプルにするために使われる。これにより、メンテナンスが容易になり、コードの可読性も向上する。また、attr_readerattr_writerで読み取り専用・書き込み専用の設定も可能。

with_optionsは、共通のバリデーションや設定をまとめて適用するために使用する。これにより、重複コードを減らし、可読性が向上される。Railsでのモデルのバリデーションやオプションの指定を簡潔に書く際に便利

データベースに購入情報(Purchase)と配送先情報(ShippingAddress)を保存するための処理を記述。

app/models/purchase_form.rb
# 中略
def save
    purchase = Purchase.create(user_id:, item_id:)

    ShippingAddress.create(
      postal_code:,
      prefecture_id:,
      city:,
      address:,
      building_name:,
      phone_number:,
      purchase_id: purchase.id
    )
  end
end

購入機能に必要なnewアクションとcreateアクションの定義

app/controllers/purchases_controller.rb
# 中略

def new
    @purchase_form = PurchaseForm.new
  end

  def create
    @purchase_form = PurchaseForm.new(purchase_params)
    if @purchase_form.valid?
      @purchase_form.save
      redirect_to root_path
    else
      render :new, status: :unprocessable_entity
    end
  end

  private

  def purchase_params
    params.require(:purchase_form).permit(:postal_code, :prefecture_id, :city, :address, :building_name,
                                          :phone_number).merge(user_id: current_user.id, item_id: params[:item_id])
  end
end

ルーティングの修正

購入機能は、商品情報にネストされたルーティングの設定がされていなかったため修正。ネストすることで、itemsコントローラーで定義した変数を利用できるようになる。

config/routes.rb
# 中略
resources :items do
    resources :purchases, only: [:index, :new, :create]
end

indexアクション内のコード編集

app/controllers/purchases_controller.rb
def index
    @item = Item.find(params[:item_id])
    @purchase_form = PurchaseForm.new
end

1.商品の取得:

@item = Item.find(params[:item_id])の部分は、特定の商品情報をデータベースから取得する。params[:item_id]は、URLから取得した商品ID。このIDを使用して、該当する商品をデータベースから検索し、その情報を@itemに格納する。
商品の詳細情報を表示するためには、正しい商品データを取得することが必須。この情報がないと、ユーザーに対して適切な商品情報を表示することができない。

2.購入フォームの初期化:

@purchase_form = PurchaseForm.newの部分では、購入に必要な情報を入力するためのフォームオブジェクトを初期化している。これにより、購入に必要な情報(住所、電話番号など)を収集するためのフォームが準備される。
フォームオブジェクトを使用することで、入力内容の検証やデータの保存を簡単に行えるようになる。

購入のためのフォームを実装

app/views/purchases/index.htmle.erb
# 中略
<%= form_with (model: @purchase_form, url: item_purchases_path(@item.id), id: 'charge-form', class: 'transaction-form-wrap',local: true) do |f| %>
# 中略
  • url: item_purchases_path(@item.id): ここで @item.id を渡すことで、現在の商品に紐づいた購入が正しく処理される
  • model: @purchase_form: @purchase_form はフォームオブジェクトのインスタンスであり、モデルの役割を果たす。これにより、バリデーションエラーメッセージが自動的に関連フィールドに表示される

この設定で、購入データが送信される際に指定した create アクションにリクエストが届き、正しいフォーム送信ができるようになる。

現時点までの実装でフォームの情報が保存されるのか確認

Template is missingエラーが発生

該当箇所を確認

purchases_controller.rb
# 中略

render :new, status: :unprocessable_entity

# 中略

new.html.erbファイルが存在していないのにrender :newを指定してしまっていたためエラーが発生していた。
下記に修正

ruby;purchases_controller.rb
render :index, status: :unprocessable_entity

続いてNoMethodErrorが発生。
<%= image_tag @item.image, class: 'buy-item-img' %>部分が該当していた。
最初に商品購入ページへ遷移した際は、問題なく表示がされていたので、再表示される際に何かしらの問題が発生していると予想し、createアクション内を確認。
すると、@itemが再設定されていないことが確認できた。
下記にコード修正

app/controllers/purchases_controller.rb
# 中略

def create
  @item = Item.find(params[:item_id])
  @purchase_form = PurchaseForm.new(purchase_params)
  if @purchase_form.valid?
    @purchase_form.save
    redirect_to root_path
  else
    render :index, status: :unprocessable_entity
  end
end

ここでnewアクションとcreateアクションで@item = Item.find(params[:item_id])が共通して使用されていたため、privateメソッド内にset_itemメソッドを定義し、before_actionで呼び出せるように修正
※コード記載は省略。

テストコードを実行する

ここまでの実装が正しいかをテストコードを用いて確認

次回はPAY.JPを利用してクレジットカード決済ができるように実装を進めていきます!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?