🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Ruby on Rails

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

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

データベース設計

データベース設計はデータベースの論理的や物理的な部分を特定する工程です。

Q&A

解決済

2回答

2852閲覧

レシピサイトのDB設計 中間テーブルの必要性

yumi_1003

総合スコア1

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Ruby on Rails

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

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

データベース設計

データベース設計はデータベースの論理的や物理的な部分を特定する工程です。

0グッド

0クリップ

投稿2021/02/08 13:38

編集2021/02/08 14:32

前提・実現したいこと

初投稿・プログラミングを初めて2ヶ月のものです。

DB設計において、中間テーブルを使うパターンとFormオブジェクトを使うパターンのどちらがプログラミングでは正しいのか、お詳しい方に助言をいただけたらと思います。

レシピサイトを作成しています。
  • menusテーブル ・・・ レシピの名前、作り方
  • foodstuffsテーブル ・・・ 材料、分量、何人前か

初期段階ではこちらのようなテーブル設計で実装していました。

しかし、一つのForm画面から、二つのテーブルに保存したいので、
Formオブジェクトを使えば良いのでは?と考え、こちらの形に変更いたしました。

CREATE TABLE

usersテーブル

ColumnTypeOptions
nicknamestringnull: false
emailstringnull: false, unique: true
encrypted_passwordstringnull: false

Association

  • has_many :menus
  • has_many :comments

menusテーブル

ColumnTypeOptions
titlestringnull: false
recipetextnull: false
hour_idintegernull: false
price_idintegernull: false
userreferencesnull: false, foreign_key: true

Association

  • belongs_to :user
  • has_one :foodstuff
  • has_many :menu_tags
  • has_many :tags, through: menu_tags
  • has_many :comments

commentsテーブル

ColumnTypeOptions
commentstring
userreferencesnull: false, foreign_key: true
menureferencesnull: false, foreign_key: true

Association

  • belongs_to :user
  • belongs_to :menu

foodstuffsテーブル

ColumnTypeOptions
foodstuff_namestringnull: false
quantitystringnull: false
servingintegernull: false
menureferencesnull: false, foreign_key: true

Association

  • belongs_to :menu
  • has_many :menus, through: foodstuff_menus
  • has_many :foodstuff_menus

foodstuff_menusテーブル

ColumnTypeOptions
foodstuffreferencesnull: false, foreign_key: true
menureferencesnull: false, foreign_key: true

Association

  • belongs_to :foodstuff
  • belongs_to :menu

menu_tag_relationsテーブル

ColumnTypeOptions
menureferencesnull: false, foreign_key: true
tagreferencesnull: false, foreign_key: true

Association

  • belongs_to :menu
  • belongs_to :tag

tagsテーブル

ColumnTypeOptions
namestringnull: false

Association

  • has_many :menu_tags
  • has_many :tags, through: menu_tags

考えたこと・調べたこと

  • そもそも中間テーブルを使うときは多対多の時とのことですが、menusテーブルに対して、foodstuffs(材料)のパターンは一つしかないので中間テーブルを設けることすらおかしいのではと思いましたが。。

  • 他の質問者の方で、同様にレシピサイトの作成をしている方がいらっしゃいましたが、回答者の方は中間テーブルを推奨していました。

  • 中間テーブルを通過してFormオブジェクトへの保存をする手法も見つかりましたが、まず中間テーブルに必要性があるのかが整理しきれずに止まってしまいました。

根本が間違えていてトンチンカンな質問をしていたら申し訳ございません。

補足情報

Ruby 6.0.0
railsを使用しての実装です。
DBはMySQLを使用しています。

追記

中間テーブルを使わない場合はこちらの実装を考えましたが、ご意見いただきたいです。
他のテーブルは上記と同じもので考えていたので省略させていただきました。

menusテーブル

ColumnTypeOptions
titlestringnull: false
recipetextnull: false
hour_idintegernull: false
price_idintegernull: false
userreferencesnull: false, foreign_key: true

Association

  • belongs_to :user
  • has_one :foodstuff

foodstuffsテーブル

ColumnTypeOptions
foodstuff_namestringnull: false
quantitystringnull: false
servingintegernull: false
menureferencesnull: false, foreign_key: true

Association

  • belongs_to :menu

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

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

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

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

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

Orlofsky

2021/02/08 13:47

データベースやそのバージョンによって方言が大きいですから、どのデータベースを使うのかを質問のタグで示したり、質問にバージョンも明記した方が適切なコメントが付き易いです。
Orlofsky

2021/02/08 13:50

質問に以下の内容を追記しては? テーブル定義はCREATE TABLEで、テーブル中のデータはINSERTで 、現行の考えられるSELECT文、その結果、希望する結果を https://teratail.com/help/question-tips#questionTips3-7 の [コード] で提示しては?
yumi_1003

2021/02/08 14:14

修正依頼ありがとうございます! 質問以前の問題があったこと失礼いたしました。 希望する結果は、コードではなく中間テーブルを使用するか、Formオブジェクトを使用するかを考えているので、すみませんがどのように記述すれば良いか分かりませんでした。。
Orlofsky

2021/02/08 14:23

中間テーブルを使わないでどんなSELECT文になるかを提示できると良かったのですが。
yumi_1003

2021/02/08 14:35

考えが浅はかでした。ご指摘ありがとうございます! 追記にて中間テーブルの無いものを考えました。 もしよろしかったらまたご指摘等いただけたら嬉しいです...!
hentaiman

2021/02/08 14:56 編集

rubyが分からないので質問がちょっと見難いので軽いアドバイスですが、まずは中間テーブルを使わない形で作ってみれば良いです。 そして実際の利用を想定していそれなりにレシピデータを登録してみましょう。その時に、同じデータの保存し過ぎじゃん!みたいな感想を持ったなら中間テーブルを作れば良いし、特に気にならないなら持たなくて良いです。 不特定多数が使うシステムなら冗長なデータを避けるに越したことは無いし、他にも都合が良い事が多いですが、自分専用のレシピ公開だったら冗長なデータの持ち方をしたところで大した量のデータでは無いので気にする事は無いかもしれません。 中間テーブルを作らない事で機能の実装に不都合があれば中間テーブルを作るという考え方でも。
yumi_1003

2021/02/08 23:25

貴重なご意見ありがとうございます!
guest

回答2

0

ベストアンサー

中間テーブルを使うかどうかと Form オブジェクトを使うかどうかは別問題です。
これは分けて考えるようにしてください。

基本的に、DB 設計は Web アプリケーションの実装に依存することはありません。
どんなデータをどういう風に扱うかによって決めることになります。
実際は Web アプリケーションが扱いやすいように DB 設計を寄せることは普通に行われるので依存しないってことはないんですが、原則的にそうだと思ってください。

で、ここで問題になるのはメニューと材料のデータとその関係性です。
これはやろうとしていることによるのでこれが正解とは一概に言えないのですが、私だったらこんな風にします。

  • foodstuffs テーブルは food_stuffs テーブルに名前を変える
  • 中間テーブルは使用する( menu_food_stuffs かな?)
  • food_stuffs の quantity(分量) は 中間テーブル側に保持する。
  • food_stuffs の serving(何人前か) は menu テーブルに移す(何人前かって材料に持つ意味ないのでは。。)

こうする理由は、menu -> food_stuff だけではなく food_stuffs -> menu でデータを辿るユースケースを考えると分かりやすいかもしれません。材料名でメニューを検索したいときに、その材料名をプルダウンメニューにしたいってとき、どっちが向いているかなと考えてみると。。
また、材料名を毎回入力させてしまうと、例えば人参、ニンジン、にんじんなどの表記揺れや入力ミスが起こりやすくなります。
材料名は food_stuff で管理されていて、基本的に登録されているものから選ぶ(ない場合に限り新規追加)の仕組みにしておいた方が効率が良くなります。
例えばその後英語表記に対応させたい場合、food_stuff に english_name カラムを追加してそれぞれの材料に対応する英語、例えば carrot を登録するってやれば済みます。レコード一個だけ。
中間テーブルを使わない場合、にんじんが材料として使われている分だけレコードの修正が必要になったりします。

この材料テーブルは基本的に tag テーブルと同じ性格を持っています。
集約できるデータは集約させる(正規化と言います)ようにしておかないと後々の機能追加に追従する柔軟性が失われたり、RDBMS が本来もつ性能を発揮できなかったりします。

この辺りは慣れもあり、非効率な設計にどんな問題があるのか。字面で解説されてもよく分からないかもしれません。
中間テーブルを使わない設計でも機能的には動かせると思うので、とりあえずそれでやってみるのもいいと思いますよ。
実運用していると問題に気づきやすいんですけどね。

投稿2021/02/08 19:57

oakbow

総合スコア227

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

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

yumi_1003

2021/02/08 23:29

具体的な説明と貴重なご意見ありがとうございます! DBとFormオブジェクトを天秤にかけてる事自体おかしかったことに気がつけませんでした。再度DBについて学習してからまた実装に戻ります。 本当にありがとうございます!
oakbow

2021/02/09 02:53

DB設計は難しいですよね。どうしても実際のアプリケーションで経験を積まないと理解が難しいので時間がかかる面があります。その反面、言語やフレームワークに依存せず長く使える知識になるので、ゆっくり頑張ってください。
guest

0

テーブル設計をきちんと勉強しなかった人がハマるようです。過去ログをじっくりと読む、って勉強方法も良いかと。過去ログを中間テーブルの検索結果

投稿2021/02/08 17:08

Orlofsky

総合スコア16417

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

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

yumi_1003

2021/02/08 23:31

申し訳ございません。学習不足でした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問