丸3日データベースに保存されない状態に悩んだ部分です。
モデル間の関係性、記述方法、メソッドの使い方がややこしかった部分です。
モデルファイルに絞ってまとめます。
購入機能があるアプリで購入すると配送先情報がorderテーブルへ、購入履歴がpurchaseテーブルへそれぞれ保存される状態を目指します。
1.model配下にorder_fomr.rbを作成
このファイルにorder.rbとpurchase.rbに記述するべきカラム、バリデーション、保存する処理を記述していく。
class OrderForm
include ActiveModel::Model
end
新たなクラスを定義し、include ActiveModel::Modelでform_with や render などのヘルパーメソッドの引数として扱え、バリデーションの機能を使用できるようにする。
2.それぞれのモデルで扱うカラムをすべて記述
class OrderForm
include ActiveModel::Model
#orderテーブル、purchasesテーブルのカラムを書く
attr_accessor :post_code, :region_id, :city, :house_number, :building_name, :tel, :item_id, :user_id
end
ここで、orderテーブルにはpurchase_idが入りそうな気がしますが、purchase_idはorderが保存されてから生成されるのでこの時点で記述の必要はない。
purchaseは購入履歴なのでorderが済んでから、という考え方。
3.バリデーション
class OrderForm
include ActiveModel::Model
#orderテーブル、purchasesテーブルのカラムを書く
attr_accessor :post_code, :region_id, :city, :house_number, :building_name, :tel, :item_id, :user_id
#purchase_idはorderが保存されてから生成されるので不要
with_options presence: true do
validates :post_code, format: { with: /\A[0-9]{3}-[0-9]{4}\z/, message: "はハイフンあり7桁で入力して下さい" }
validates :region_id, numericality: { other_than: 1, message: 'を選択してください' }
validates :city
validates :house_number
validates :tel, format: { with: /\A\d{10,11}\z/, message: "はハイフンなし10桁か11桁で入力して下さい" }
validates :item_id
validates :user_id
end
with_options presence: true doでdo ~ end内のバリデーションはpresence: trueであることをまとめられる。
order.rbとpurchase.rbにバリデーションを記述する必要はない。
4.データ保存の処理
class OrderForm
include ActiveModel::Model
#orderテーブル、purchasesテーブルのカラムを書く
attr_accessor :post_code, :region_id, :city, :house_number, :building_name, :tel, :item_id, :user_id
#purchase_idはorderが保存されてから生成されるので不要
with_options presence: true do
validates :post_code, format: { with: /\A[0-9]{3}-[0-9]{4}\z/, message: "はハイフンあり7桁で入力して下さい" }
validates :region_id, numericality: { other_than: 1, message: 'を選択してください' }
validates :city
validates :house_number
validates :tel, format: { with: /\A\d{10,11}\z/, message: "はハイフンなし10桁か11桁で入力して下さい" }
validates :item_id
validates :user_id
end
def save #attr_accessorの値をそれぞれのテーブルに分ける
#購入履歴を保存。orderでpurchase_idを使うので代入しておく。
purchase = Purchase.create(item_id: item_id, user_id: user_id)
#配送先情報を保存
Order.create(post_code: post_code, region_id: region_id, city: city, house_number: house_number, building_name: building_name, tel: tel, purchase_id: purchase.id, user_id: user_id, item_id: item_id)
end
end
ここで先ほどattr_accessorでは記述不要としたpurchase_idが出てくる。
Orderがcreateされたタイミングでpurchase_idは必要になるのでpurchase.idとして追加する。
attr_accessorの値を各テーブルに一つずつもれなく振り分ける、というイメージでいたのでOrder.createにitem_id,user_idの記述が足りないことに気づけず苦戦しました。
そしてpurchase.idの生成されるタイミングも難しかったポイントです。
紙に書きだして、一つずつ理解しながら進めていって解決できました。
頭の中でイメージするだけではうまく組み立てられないので、今後も紙ベースは使っていこうと思います。