質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby on Rails 4

Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

Q&A

解決済

2回答

3129閲覧

多対多の関連付け(modelの書き方が正しいか)

innjera

総合スコア132

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby on Rails 4

Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

0グッド

0クリップ

投稿2017/01/17 03:44

編集2017/01/18 03:34

ユーザー(出品者)がサービス(商品)を出品し、別のユーザー(購入者)がそれを購入できるというケースを想定した場合、以下の考え方で正しいでしょうか?誤りがあればご指摘頂けますと幸甚です。

###前提
・ユーザー(出品者)とサービス (商品): 1対多の関連付け
・サービス(商品)とユーザー(購入者) : 多対多の関連付け *1つのサービス(商品)に複数のユーザー(購入者)が購入できる前提。
・ユーザーは出品者にも購入者にもなれる : 出品者と購入者は同じmodel

##モデル(正しいでしょうか?)
・上記前提を元にすると、必要となるmodelUserProductEntry(productとそれを買うuser(購入者))を多対多の関連付けで使用する中間テーブル)の3つ

・すなわち、以下のイメージ
user (1)<-> (多)product(1) <-> (多)entry(多) <->(1) user

###各モデルのテーブル(migration file) *単純化してます
User

ruby

1#User 2class CreateUsers < ActiveRecord::Migration[5.0] 3 def change 4 create_table :users do |t| 5 t.string :email, null: false # メールアドレス 6 t.string :family_name # 姓 7 t.string :given_name # 名 8 t.string :address # 住所 9 t.text :user_profile # プロフィール 10 t.string :hashed_password # パスワード 11 12 t.timestamps 13 end 14 end 15end 16 17#Product 18class CreateProducts < ActiveRecord::Migration[5.0] 19 def change 20 create_table :products do |t| 21 t.references :user #外部キー 22 t.integer :price #価格 23 t.string :title #タイトル 24 t.datetime :posted_at #商品投稿日 25 t.binary :data #写真 26 t.timestamps null: false 27 end 28 end 29end 30 31#Entry 32class CreateEntries < ActiveRecord::Migration[5.0] 33 def change 34 create_table :entries do |t| 35 t.references :product, null: false 36 t.references :user, null: false 37 t.timestamps 38 end 39 end 40end 41

###各モデルの書き方

ruby

1#Userモデル 2class User < ApplicationRecord 3 has_many :products, dependent: :destroy 4 has_many :applied_products, through: :entries, dependent: :destroy, source: :product 5 has_many :entries, dependent: :destroy 6end 7 8#Productモデル 9class Product < ApplicationRecord 10 belongs_to :user 11 has_many :entries, dependent: :destroy 12 has_many :applicants, through: :entries, source: :user 13end 14 15#Entryモデル 16class Entry < ApplicationRecord 17belongs_to :applied_products, class_name: "Product", foreign_key: "product_id" 18belongs_to :applicants, class_name: "User", foreign_key: "user_id" 19end 20 21

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

IPU

2017/01/18 03:14

modelの紐付けの前に、どんなテーブルで作る予定かを書かないと伝わりづらいと思います。
innjera

2017/01/18 03:34

情報かけており申し訳ありません。今しがた編集致しました。宜しくお願い致します。
guest

回答2

0

同じ種類の「商品」が複数あった場合、それらの商品の集まりを"1つの物"としてとらえる考え方と、個々の商品をそれぞれ"1つの物"としてとらえる考え方がありますが、個々の商品を"1つの物"として扱う方が考えやすいです。
というのは、複数の商品をひとまとめで考えると、購入者ごとの購入数の合計が商品数を超えないように常に状態を管理する必要があるので、複雑になるからです。

個々の品物をそれぞれ"1つの物"とするなら、
・ユーザー(出品者)と商品 : 1対多の関連付け (ある品物を出品するのは一人だけ、但し一人が複数の品物を出品できる)
・商品とユーザー(購入者) : 多対1の関連付け (ある品物を購入するのは一人だけ、但し一人が複数の品物を購入できる)
になります。

ある人は出品者にも購入者にもなれる。
しかし売買に関する役割(role)が異なりますから、出品者と購入者のモデルは別々にしたほうが素直だと思います。
そうすれば1つの商品に関した関係が、下記のように単純なものになるからです。
(購入者が居ない状態では、buyerが存在しない関係になります)

seller(出品者) - item(個別の商品) - buyer(購入者)

投稿2017/01/17 07:34

coco_bauer

総合スコア6915

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

innjera

2017/01/17 08:06

コメント有難う御座います! 初歩的な質問で恐縮ですが、「出品者と購入者のモデルは別々にしたほうが素直」という点が、良く理解できませんでした。 Aというユーザーが、出品もするし購入もする場合に、モデルを分けてしまうと、(例えばですが)ユーザー情報(氏名やパスワード等)をもつデーターベースを作成する為に、①seller modelのmigrationファイルと②buyer modelのmigrationの2つを作成(ほぼ同一のcolumnを持つmodel/data baseを2つ作る)ことにならないでしょうか?
guest

0

ベストアンサー

・上記前提を元にすると、必要となるmodelはUserとProductとEntry(productとそれを買うuser(購入者))を多対多の関連付けで使用する中間テーブル)の3つ

やりたい事に対して、この構成の作り方は、正しいと思います。
1番シンプルですね。

ただし、テーブルを見ると、Entryのカラムが足りないですね。
このままだと、ユーザと商品の紐付けはわかりますが、ユーザの立場(出品or購入)がわかりません。
Entryテーブルに、出品or購入がわかるようなflag用のカラムを増やしてあげると、やりたい事が出来る構成になるはずです。

本題のmodelの紐付け部分ですが、

・すなわち、以下のイメージ

user (1)<-> (多)product(1) <-> (多)entry(多) <->(1) user

ここも少し違いますね。
書き方を合わせて書くと、
product(1) <-> (多)entry(多) <->(1) user
だけですね。

では、これをどうコード化するかと言うと、

ruby

1# app/models/user.rb 2class User < ActiveRecord::Base 3 has_many :entries 4 has_many :products, through: :entries 5end 6 7# app/models/entry.rb 8class Entry < ActiveRecord::Base 9 belongs_to :user 10 belongs_to :product 11end 12 13# app/models/product.rb 14class Product < ActiveRecord::Base 15 has_many :entries 16 has_many :users, through: :entries 17end

こうですね。
以下のサイトがほとんど同じことをやっているので、参考に読んでみてください。
Rails4で多対多のリレーションをモデルに実装する

あと、余談ですが、dependent: :destroyは今回のケースでは使わない方が良いと思いますよ。
ユーザを削除したりしても、関連する商品を消されては困るはずなので。

投稿2017/01/18 05:00

IPU

総合スコア283

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

innjera

2017/01/18 22:45

種々アドバイス有難うございます!よく理解できました。
innjera

2017/01/18 23:43

いただいたアドバイスを踏まえ、最終的にこうしてみました。 #User model has_many :entries_of_adviser, :class_name => 'Entry', :foreign_key => 'adviser_id' has_many :entries_of_applicant, :class_name => 'Entry', :foreign_key => 'applicant_id' has_many :products_of_adviser, :through => :entries_of_adviser, :source => 'product' has_many :products_of_applicant, :through => :entries_of_applicant, :source => 'product' #Product モデル has_many :advisers, :through => :entries has_many :applicants, :through => :entries has_many :entries #Entryモデル belongs_to :adviser, :class_name => 'User' belongs_to :applicant, :class_name => 'User' belongs_to :product
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問