iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 13
0
自我挑戰組

Ruby on Rails 新手的30個問題!系列 第 13

Day_13 model 一對多? & 部落格文章系統

嗨!各位朋友大家好,打給後,歹嘎吼,胎尬喉,我是阿圓,一樣有請今天的one piece:

( model 關聯性就像海軍的階級啊!)

model 一對多?

部落格接下來要進展到文章的階段了,在此之前,先來講一下 model 關聯性吧。

關聯性?

什麼是關聯性, Rails 將 model 用分層級的方式來連接 model (可以用上司下屬的感覺去聯想),也就是透過宣告的方式,讓 a model 屬於 b model ,而這樣的方法可以讓在建立資料的時候簡單很多,因為 Rails 會幫你做出好用的方法,以官方文件的例子來說:

若不設立關聯性,在建立一筆屬於顧客的訂單時,必須在建立的時候在指定一個顧客id給他:

@order = Order.create(order_date: Time.now, customer_id: @customer.id)

若要刪除顧客及他所有的訂單又更麻煩了,要先將訂單都撈出來,一筆一筆刪掉後,再刪顧客:

@orders = Order.where(customer_id: @customer.id)
@orders.each do |order|
  order.destroy
end
@customer.destroy

而使用關聯性的情況:

class Customer < ActiveRecord::Base
  has_many :orders, dependent: :destroy
end
 
class Order < ActiveRecord::Base
  belongs_to :customer
end

建立訂單:

@order = @customer.orders.create(order_date: Time.now)

刪除顧客及他所有的訂單:

@customer.destroy

see~~~,整個程式碼都變得清爽起來了~

而 model 之間彼此的關聯性主要有三種:

  1. 一對一
  2. 一對多
  3. 多對多

我主要會著重在一對多跟多對多。

一對多關聯性

has_many

用部落格的方式去想,一個 admin 會有很多的 post

class Admin < ActiveRecord::Base
  has_many :posts #盡量是複數喔!
end

這樣的話,rails 對於 admin,會生出一些方法可以用:

admin1 = Admin.first
post1 = Posts.first
#===========#
admin1.posts # 可以列出admin1的所有文章,是一個陣列
admin1.posts = posts1 #把 post1 這篇文章指定給 admin1
#請注意,這樣是把 admin1 的所有文章砍掉只剩 post1 喔,若是要新增,請使用 
admin1.posts << posts1

admin1.posts.build(title:'一對多關聯性')
#用admin1的角度,建立一篇標題為'一對多關聯性的'文章
#要再呼叫save方法才會存入資料庫
admin1.posts.create(title:'一對多關聯性')
#同上,不過不需呼叫save方法

belongs_to

而這些 posts 會屬於 admin。

class Post < ActiveRecord::Base
  belongs_to :admin #盡量是單數喔!
end

一樣,對於 post,會生出一些方法可以用於反查:

admin2 = Admin.second
post2 = Posts.second
#===========#
post2.admin # 列出 post2 的作者
post2.admin = admin2 #把post2的作者,指定為admin2

迷思

  1. 我在資料的欄位裡面有一個 admin_id 的欄位就有關聯了嗎?
    沒有!資料表是資料表,你只是開了一個欄位給他用,而這個欄位會寫上一個數字,剛好是 admin 的 id ,但不代表有關聯性,請去 model 指定關聯性給他們。
  2. 設定 has_many 後,一定要有 belongs_to 嗎?
    不用!如果不需要做到反查的動作,就不需要設定 belongs_to

接著讓我們進行部落格實作的部分!

部落格實作

debug

昨天發現一個bug,我current_admin的方法寫錯了,囧"

請聽我娓娓道來:
admin 登入後會有一個發一個session[:admin_token]給他,但我沒有讓它存在任何一個欄位裡,根本就找不到這個 admin 啊!
所以我對admin的資料表多開一個欄位放 token,並將 sign_in 跟 current_admin 的部份改寫了一下:

# admin_controller
private
def sign_in_admin(admin)
  session[:admin_token] = SecureRandom.uuid
  admin.update(token: session[:admin_token])
end 
# application_controller
def current_admin
  @current_admin ||= Admin.find_by(token: session[:admin_token])
end

其實也可以使用環境變數寫死,不過這樣在之後上線的時候會需要設定比較多東西~所以我選擇開一個欄位~

posts

接著我們進行到文章的部分,有些重複的動作我一樣寫概略,這部分會著重在model那邊。

  1. 先去 routes.rb ,指定一下posts的路徑
  2. 建立 posts_controller
  3. 建立7個 action
  4. 開始建立 model

一樣先來想一下我們的資料裡們會需要有哪些欄位?

  1. 標題:string
  2. 內文:string
  3. admin_id:integer

其中 admin_id 就是為了最上面所說的一對多關聯性,而建立model的時候,可以用rails g model Post title content admin_id:references

:references的話,會自動去model幫你加上belongs_to :admin,降低寫錯的機率!

好的,明天我們再來繼續多對多關聯性以及文章分類的部分,感謝各位看到這邊,若有任何建議,請各位不吝指教!我們明天見!

部落格GitHub

參考文章

為你自己學 Ruby on Rails
官方文件


上一篇
Day_12 migration? & 部落格的個人檔案
下一篇
Day_14 model 關聯性 多對多? & 部落格分類系統
系列文
Ruby on Rails 新手的30個問題!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言