iT邦幫忙

2021 iThome 鐵人賽

DAY 26
0
自我挑戰組

海邊囝仔帶阿公阿嬤一起學 Ruby On Rails 系列 第 26

Day-26 : Model 一對一

Model之間的關聯,主要分為三個

  1. 一對一:每位使用者(User)可以開一家店(Store)
  2. 一對多:每家店(Store)可以賣很多商品(Product)
  3. 多對多:每家店(Store)除了可以賣很多商品,每個商品也可以在很多店家做販售

開始先來說明,一對一

建立User Model
https://ithelp.ithome.com.tw/upload/images/20211010/20140259W9qF67Zpti.png

建立Store Model
https://ithelp.ithome.com.tw/upload/images/20211010/20140259i6pvINphLt.png

其中在Store Model內有一個叫做user_id的欄位,為什麼要有他呢?

  1. user_id這欄位的型態是數字,主要對應User Model內的id欄位,又稱之為外部鍵(Foreign Key)
  2. Rails裡的慣例是,要被對到的那個Model的名字加上_id
  3. 當然不是加上這些就會有關聯

在Model設定關聯
https://ithelp.ithome.com.tw/upload/images/20211010/201402597uUYRgK3S1.png

User Model內 寫入has_one :store
https://ithelp.ithome.com.tw/upload/images/20211010/20140259Eds0ClZnAE.png

Store Model內 寫入belongs_to :user
https://ithelp.ithome.com.tw/upload/images/20211010/20140259sIYgCk4nAr.png


進入rails console
1.用new方法建立一個使用者

user1 = User.new(name:"瓦力")
 => #<User id: nil, name: "瓦力", email: nil, tel: nil, created_at: nil, updated_at: nil>

2.用new方法建立一間商店

store1 = Store.new(title:"良心商店")
 => #<Store id: nil, title: "良心商店", tel: nil, address: nil, user_id: nil, created_at: nil, updated_at: nil>

3.把store1指定給user1

> user1.store = store1
 => #<Store id: nil, title: "良心商店", tel: nil, address: nil, user_id: nil, created_at: nil, updated_at: nil>

4.呼叫save方法:

> user1.save
  TRANSACTION (0.1ms)  begin transaction
  User Create (0.6ms)  INSERT INTO "users" ("name", "created_at", "updated_at") VALUES (?, ?, ?)  [["name", "瓦力"], ["created_at", "2021-10-10 09:46:27.212424"], ["updated_at", "2021-10-10 09:46:27.212424"]]
  Store Create (0.1ms)  INSERT INTO "stores" ("title", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["title", "良心商店"], ["user_id", 1], ["created_at", "2021-10-10 09:46:27.230607"], ["updated_at", "2021-10-10 09:46:27.230607"]]
  TRANSACTION (0.6ms)  commit transaction
 => true
這時候兩筆資料都回存在個別的資料表裡,並從store1的user_id欄位設定成user1的id

除了上面的個別新增兩個物件,在設定關聯外,也可以從(User的角度來建立商店)
1.使用new方法來建立User物件

 > user2 = User.new(name:"三眼怪")
 => #<User id: nil, name: "三眼怪", email: nil, tel: nil, created_at: nil, updated_at: nil>

2.使用build_store方法,建立Store物件

> user2.build_store(title:"三眼怪行星")
 => #<Store id: nil, title: "三眼怪行星", tel: nil, address: nil, user_id: nil, created_at: nil, updated_at: nil>

3.呼叫save方法,把兩筆資料一起存入資料表中

> user2.save
  TRANSACTION (0.2ms)  begin transaction
  User Create (1.1ms)  INSERT INTO "users" ("name", "created_at", "updated_at") VALUES (?, ?, ?)  [["name", "三眼怪"], ["created_at", "2021-10-10 09:51:10.415498"], ["updated_at", "2021-10-10 09:51:10.415498"]]
  Store Create (0.2ms)  INSERT INTO "stores" ("title", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["title", "三眼怪行星"], ["user_id", 2], ["created_at", "2021-10-10 09:51:10.420409"], ["updated_at", "2021-10-10 09:51:10.420409"]]
  TRANSACTION (0.8ms)  commit transaction
 => true
這樣可以看到user_id的資料被設定成為user_2的id,此外,若我們中間有使用build_store換成create_store,則不需要在乎叫save直接從入資料表中囉。

反之,當我們在has_one的Store Model裡加上belongs_to方法,Store Model也會多出user跟user=方法,可以直接讓我們從Store直接存取User的資料,讓我們舉個例子:

 > store1 = Store.first
  Store Load (0.4ms)  SELECT "stores".* FROM "stores" ORDER BY "stores"."id" ASC LIMIT ?  [["LIMIT", 1]]
 => #<Store id: 1, title: "良心商店", tel: nil, address: nil, user_id: 1, created_at: "2021-10-10 09:46:27.230607000 +0000", updated_at: ...

因為我們有設定belongs_to :user,所以可以直接用user方法對應這筆資料裡的User物件

> store1.user
 User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "瓦力", email: nil, tel: nil, created_at: "2021-10-10 09:46:27.212424000 +0000", updated_at: "2021-10-10 09:46:27.212424000 +0000">
仔細看上方,這是一段SQL語法!!!

當我們下了store1.user方法後,這時候Model就會去幫你查,
請問在users這個表格裡,有沒有id與我這個store1的user_id值是相同的呢?,
一個方法做出所有事,是不是相當方便~完全符合工程師懶惰的性格XDDD

謝謝大家,今天就分享到這兒~

參考資料:為自己學Ruby on Rails


上一篇
Day-25: Ruby 世界好多等於,係蝦米毀?
下一篇
Day-27 : Model 一對多
系列文
海邊囝仔帶阿公阿嬤一起學 Ruby On Rails 30

尚未有邦友留言

立即登入留言