大綱
class_name、foreign_key and primary_key
# 檔案:app/models/user.rb
class User < ApplicationRecord
has_many :stores
end
# 檔案:app/models/store.rb
class Store < ApplicationRecord
belongs_to :user
end
Store model 裡面的 foreign key 是 user_id 的話,便可以順利的將這兩個 model 關聯起來。但是如果我們想要將 store.user 改成 store.owner 呢?由於很多參數 Rails 都幫我們預設好了,因此如果我們改寫的話就要將那些參數補進去。
請參考修正如下:
# 檔案:app/models/user.rb
class User < ApplicationRecord
has_many :stores
end
# 檔案:app/models/store.rb
class Store < ApplicationRecord
belongs_to :owner, class_name: 'User', primary_key: :id, foreign_key: :user_id
end
透過上述 Store Model 程式碼的修正,就能將原先 user 與 store 的關聯,改成 owner 與 store 的關聯。
Source
這個運用的情境,通常是 Model 間的多對多關係時。
請看以下範例:
# 檔案:app/models/drink_store.rb
class Drink < ApplicationRecord
belongs_to :user
has_many :drink_store_menus
has_many :drinks, through: :drink_store_menus
end
# 檔案:app/models/drink.rb
class Drink < ApplicationRecord
has_many :drink_store_menus
has_many :drink_stores, through: :drink_store_menus
end
如果需要把 drink.drink_stores 改寫成 drink.drink_areas 的話,我們就得指定 source,因為 Rails 原本是預設會去中間表找 drink_store 欄位,而我們現在改成 drink_area 就得加入 source: drink_store。
請參考修正如下:
# 檔案:app/models/drink_store.rb
class Drink < ApplicationRecord
belongs_to :user
has_many :drink_store_menus
has_many :drinks, through: :drink_store_menus
end
# 檔案:app/models/drink.rb
class Drink < ApplicationRecord
has_many :drink_store_menus
has_many :drink_areas, through: :drink_store_menus, source: :drink_stores
end
Scope 參數
當想要在關聯裡面撈出特定的資料的時候,可以透過 scope 參數來訂定找資料的規則。
請看以下範例:
# 檔案:app/models/post.rb
class Post < ApplicationRecord
belongs_to :user
end
# 檔案:app/models/user.rb
class User < ApplicationRecord
has_many :posts, dependent: :destroy
has_many :self_posts, -> { where(draft: false) }, class_name: 'Post', dependent: :destroy
end
從上面的範例可以看到我們撈兩種不同的 post 資料,一種是全部類型的 post,另外一種是 draft 為 false 的 post。透過在第二個參數加入 -> { where(draft: false) },我們就可以輕易地在 Model 層進行篩選資料的動作了!
inverse_of
簡單的來說就是兩點:
dependent: :destroy、dependent: :nullify
請看以下範例:
# 檔案:app/models/candidate.rb
class Candidate < ApplicationRecord
has_many :vote_logs, dependent: :destroy
end
belongs_to optional: true
透過 optional: true 可以允許 event 沒有 category 的情況。
請看以下範例:
# 檔案:app/models/post.rb
class Event < ApplicationRecord
belongs_to :category, optional: true
end