4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Ruby on Rails アソシエーションの応用 class_name 【一つのモデルを複数に分岐する】

Last updated at Posted at 2020-02-19

忘れているかもしれないので、
まずは基本から復習していきましょう!!

基本(1対多)

userが複数の商品(products)を保持している関係だとしたら、

user.rb
class User < ApplicationRecord
  has_many :products
end

productsはuserに保持されているので、

product.rb
class Product < ApplicationRecord
  belongs_to :user
end

userというフォルダに、複数のproductファイルがある感覚と同じ。
スクリーンショット 2020-02-20 0.21.45.png

だから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を複数保有しているので同じです。
(次にやります。)

user.rb
class User < ApplicationRecord
  has_many :products
end

productsに紐づくuserを"seller"と"buyer"に分けたいので、下記ようにします。

product.rb
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に紐づいていました。

product.rb
class Product < ApplicationRecord
  belongs_to :user
end

belongs_to :userと記述されていますが、この"user"という名前を変えられます。
「userじゃなくて、ownerに変えたいなあ??」
このように名前を変えたい場合にclass_nameを使います。

product.rb
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テーブルをみてください。
スクリーンショット 2020-02-20 0.33.06.png
productレコードのカラムに"buyer_id(user_id)"と"seller_id(user_id)"があります
このカラムに入れるidを元にuserをsellerとbuyerに分けています。

product.rb
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を複数に分ける

販売中、売却済み、購入した商品に分けます。

販売中だけ習得する
スクリーンショット 2020-02-20 1.47.52.png

売却済みだけ取得する
スクリーンショット 2020-02-20 1.49.58.png

購入した商品だけ取得する
スクリーンショット 2020-02-20 1.51.41.png

user.rb
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

参考リンク

【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】

railsアソシエーションオプションのメモ
アソシエーションにおけるclass_nameの定義!

4
5
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
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?