忘れているかもしれないので、
まずは基本から復習していきましょう!!
基本(1対多)
userが複数の商品(products)を保持している関係だとしたら、
class User < ApplicationRecord
has_many :products
end
productsはuserに保持されているので、
class Product < ApplicationRecord
belongs_to :user
end
userというフォルダに、複数のproductファイルがある感覚と同じ。
だからuserは単数形、productは複数形
productは親フォルダのuserに入っているから、belongs_to :user
userフォルダはたくさんのproductを持っているから、 has_many :products
応用(1対多): class_name
じゃあ、productsを保持するuserが、販売者(seller)・購入者(buyer)に分ける場合はどうしましょうか?
seller・buyerにそれぞれモデルは必要ありません。userモデルを分けてあげれば大丈夫です。じゃないとIDが変わって逆に大変ですから。
userはproductsを複数保有しているので同じです。
(次にやります。)
class User < ApplicationRecord
has_many :products
end
productsに紐づくuserを"seller"と"buyer"に分けたいので、下記ようにします。
class Product < ApplicationRecord
belongs_to :seller, class_name: "User", foreign_key: "seller_id"
belongs_to :buyer, class_name: "User", foreign_key: "buyer_id"
end
「なんじゃこりゃ!!」、となったと思います。要点を抑えたら簡単です。
では解説していきます。
STEP1 モデル名は変えられる。
基礎だと下記のように、ProductはUserに紐づいていました。
class Product < ApplicationRecord
belongs_to :user
end
belongs_to :userと記述されていますが、この"user"という名前を変えられます。
「userじゃなくて、ownerに変えたいなあ??」
このように名前を変えたい場合にclass_nameを使います。
class Product < ApplicationRecord
belongs_to :owner, class_name: "user" # belongs_to :userと同じです。
# 元はUserモデルだけど(class_name: "user")、ownerって表示に変えますわ(belongs_to :owner)
end
STEP2: Userモデルを分ける
1つだとSTEP1だけで変えられます(まあ、変える必要ないんだけど)。
では、userをsellerとbuyerと2つに分けたい場合、どうすればいいのでしょうか?
まずはproductsテーブルをみてください。
productレコードのカラムに"buyer_id(user_id)"と"seller_id(user_id)"があります
このカラムに入れるidを元にuserをsellerとbuyerに分けています。
class Product < ApplicationRecord
belongs_to :seller, class_name: "user", foreign_key: "seller_id"
# belongs_to :seller, class_name: "user" = (Productに紐づく) Userモデルをsellerと定義するわ。
# foreign_key: "seller_id" = user_idはProductレコードの『seller_idカラム』のid番号を使うわ
belongs_to :buyer, class_name: "user", foreign_key: "buyer_id"
# belongs_to :buyer, class_name: "user" = (Productに紐づく) Userモデルをbuyerと定義するわ。
# foreign_key: "seller_id" = user_idはProductレコードの『buyer_idカラム』のid番号を使うわ
end
これで二つに分けられました。
カラムに紐づくid番号で分けたあげた分けです。
STEP3: Productを複数に分ける
販売中、売却済み、購入した商品に分けます。
class User < ApplicationRecord
# 全部取得
has_many :products
# 販売中
has_many :selling_products, class_name: "product", foreign_key: "seller_id", -> { where("buyer_id is NULL") }
# Productモデル名を selling_productsに定義するわ = has_many :selling_products, class_name: "product"
# productレコードの”seller_id”カラムに自分のidが入っている、productだけ取得するね = foreign_key: "seller_id" ( userはhas_many: productsだから )
# でも、buyer_idが入っていないproductだけにする = -> { where("buyer_id is NULL") }
# 買った商品
has_many :bought_products, class_name: "product", foreign_key: "buyer_id"
# Productモデル名を bought_productsに定義するわ = has_many :bought_products, class_name: "product"
# productレコードの”buyer_id”カラムに自分のidが入っている、productだけ取得するね = foreign_key: "buyer_id" ( userはhas_many: productsだから )
# 売却済み商品
has_many :sold_products, class_name: "product", foreign_key: "seller_id", -> { where("buyer_id is not NULL") }
# Productモデル名を sold_productsに定義するわ = has_many :selling_products, class_name: "product"
# productレコードの”seller_id”カラムに自分のidが入っている、productだけ取得するね = foreign_key: "seller_id" ( userはhas_many: productsだから )
# でも、buyer_idが入ってるproductだけにする = -> { where("buyer_id is not NULL") }
end
まとめ
class_nameでモデルを分ける際は、
has_many :〜側のモデルのカラムを使って分ける。
# 今回だと
has_many :products
# productにuser_idを紐づけるので、これを使って分ける。
# 親元のuserのカラムにproduct_idは入れないので、userのカラムを使って分けることはできない。
まとめ: 1対多なら、 『多』のカラムを使って分けよう ( foreign_key: )
エラーポイント
uninitialized constant
が表示された場合、class_nameが小文字になっています。
class_name: "product" = 大文字 = エラーなし
class_name: "product" = 小文字 = エラー:uninitialized constant