Day-28 : Model 多对多

今天我们要来讲多对多
什麽是多对多
举个例子:

商店has_many商品,商品也has_many商店,然後有一个第三方的资料表来存放两边Model的资讯。

接下来,奉上图解!

https://ithelp.ithome.com.tw/upload/images/20211012/20140259hY9bum9Jto.png

那我们来开始做多对多拉
1.第三方Model仅需存放两边(商店和商品)Model的id,若想要额外增加一些栏位也是可行的
https://ithelp.ithome.com.tw/upload/images/20211012/20140259sGzrYsfLMb.png

这边会用到references的写法是因为会帮我们多做几件事情

1.自动加上索引,加快查询的速度
2.自动帮Model加上belongs_to

2.执行rails db:migrate
https://ithelp.ithome.com.tw/upload/images/20211012/20140259dl7FvFu1Va.png

3.让我们来编辑planet这个档案
https://ithelp.ithome.com.tw/upload/images/20211012/20140259YO3PffuNoc.png
上面有说到,因为我们使用了references的写法,所以Ruby on Rails 会自动帮我们补上这两行

 belongs_to :store
 belongs_to :product
  1. 回到Store Model,加上下面这两行
    https://ithelp.ithome.com.tw/upload/images/20211012/20140259xYBMzmJdZk.png

5.Product Model加上这两行
https://ithelp.ithome.com.tw/upload/images/20211012/20140259cUPHgBfkND.png

Planet Model同时belongs_to Store 以及 Product这两个Model

Store 与 Product这两个Model也都has_many Planet

关系图解如下:
https://ithelp.ithome.com.tw/upload/images/20211012/20140259nJTpA6clXL.png

Store跟Product都是透过through Planet的纪录,也就是第三方,才会知道商店与商品之间的关系

接下来,进入 rails c看看
1.先取任意两间商店 => store1和 store2

> store1 = Store.find(1)
  Store Load (0.3ms)  SELECT "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
 => #<Store id: 1, title: "良心商店", tel: nil, address: nil, user_id: 1, created_at: "2021-10-10 09:...
> store2 = Store.find(2)
  Store Load (0.3ms)  SELECT "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
 => #<Store id: 2, title: "三眼怪行星", tel: nil, address: nil, user_id: 2, created_at: "2021-10-10 0...

2.随意取出2件商品 => product1和 product2

> product1 = Product.find(1)
  Product Load (0.1ms)  SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
 => #<Product id: 1, name: "吃吃喝喝商店", description: nil, price: 0.2e3, is_available: nil, store_i...
> product2 = Product.find(2)
  Product Load (0.3ms)  SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
 => #<Product id: 2, name: "我想要飞", description: nil, price: 0.1e4, is_available: nil, store_id: 1...

3.把product1, product2丢给store2,把product1, product2丢给store1

> store2.products = [product1, product2]
  Product Load (0.1ms)  SELECT "products".* FROM "products" INNER JOIN "planets" ON "products"."id" = "planets"."product_id" WHERE "planets"."store_id" = ?  [["store_id", 2]]
  TRANSACTION (0.0ms)  begin transaction
  Planet Create (0.5ms)  INSERT INTO "planets" ("store_id", "product_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["store_id", 2], ["product_id", 1], ["created_at", "2021-10-12 15:24:01.126751"], ["updated_at", "2021-10-12 15:24:01.126751"]]
  Planet Create (0.1ms)  INSERT INTO "planets" ("store_id", "product_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["store_id", 2], ["product_id", 2], ["created_at", "2021-10-12 15:24:01.128415"], ["updated_at", "2021-10-12 15:24:01.128415"]]
  TRANSACTION (0.5ms)  commit transaction
 => [#<Product id: 1, name: "吃吃喝喝商店", description: nil, price: 0.2e3, is_available: nil, store_...
 > store1.products = [product1, product2]
  Product Load (0.4ms)  SELECT "products".* FROM "products" INNER JOIN "planets" ON "products"."id" = "planets"."product_id" WHERE "planets"."store_id" = ?  [["store_id", 1]]
  TRANSACTION (0.1ms)  begin transaction
  Planet Create (0.5ms)  INSERT INTO "planets" ("store_id", "product_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["store_id", 1], ["product_id", 1], ["created_at", "2021-10-12 15:24:12.087711"], ["updated_at", "2021-10-12 15:24:12.087711"]]
  Planet Create (0.1ms)  INSERT INTO "planets" ("store_id", "product_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["store_id", 1], ["product_id", 2], ["created_at", "2021-10-12 15:24:12.089616"], ["updated_at", "2021-10-12 15:24:12.089616"]]
  TRANSACTION (1.0ms)  commit transaction
 => [#<Product id: 1, name: "吃吃喝喝商店", description: nil, price: 0.2e3, is_available: nil, store_...
  1. 查询看看,有几间商店在卖product1:
> product1.stores.count
   (0.5ms)  SELECT COUNT(*) FROM "stores" INNER JOIN "planets" ON "stores"."id" = "planets"."store_id" WHERE "planets"."product_id" = ?  [["product_id", 1]]
 => 2
> product2.stores.count
   (0.5ms)  SELECT COUNT(*) FROM "stores" INNER JOIN "planets" ON "stores"."id" = "planets"."store_id" WHERE "planets"."product_id" = ?  [["product_id", 2]]
 => 2

因为在store1和store2都有贩售product1与product2,因此为两家,我们看一下上面的SQL语法,我们就可以得知,他不再对Store与Product要资料,而是与第三方planet进行查询的动作!

与前面的差别在於,

他是跟第三方要资料!!!

今天分享到这,每天进步一点点/images/emoticon/emoticon23.gif

参考资料:为你自己学Ruby on Rails


<<:  使用 Vaadin Directory 组件显示Google地图 - day27

>>:  Day27:终於要进去新手村了-HTML DOM 基本观念

CIA安全目标

曾就「资讯本身的破坏」和「资讯或资讯系统获取或使用中断」进行了辩论。然而,FISMA和FIPS 19...

【没钱买ps,PyQt自己写】Day 18 / Project 使用 QTimer,自制码表(计时器) PyQt5 stopwatch DIY

看完这篇文章你会得到的成果图 前言 这篇我们要来学一个新的东西 QTimer! QTimer 是独立...

Day 6 - 颜色设定

和其它 CSS 框架一样,Tailwind 也内建颜色,但它不像 Bootstrap 就给那几组,...

个人笔记 维修单派工 关联表

开始绘制维修单派工关联表,画错蛮多次。我学习的方式,先在网路上找相关的图参考,思考後进行绘制动作。画...

Day 29 - BFS

大家好,我是长风青云。今天是铁人赛的29天。这是我最後一个要讲的演算法喔。 如果明天的部分不想看不想...