Membuat Relasi dengan Hanya Salah Satu Type pada Single Table Inheritance Model di Rails
Prerequisite
ruby 3.0.0
rails 6.1.2
postgresql 12.5
rspec 4.0.0
Latar Belakang Masalah
Catatan kali ini, saya akan membahas Ruby on Rails dari sisi back-end.
Melanjutkan catatan mengenai Single Table Inheritance sebelumnya, yaitu tentang Mengenal Single Table Inheritance dengan Devise pada Rails (Contoh 2).
Sekarang saya akan lanjutkan dengan relasi antar type, namun catatan kali ini mencontohkan salah satu type saja.
Misalkan saya memilik model User yang memiliki dua type user, yaitu Developer dan Copywriter.
users
id | type | |
---|---|---|
1 | bayuyuba@gmail.com | Developer |
2 | bololoba@gmail.com | Copywriter |
news
title | content | user_id |
---|---|---|
… | … | 2 |
Sudah dapat ditebak yaa, tabel news tentu memiliki relasi one to many dengan tabel users.
Karena saya menggunakan STI pada tabel Users, maka saya juga perlu membuat model untuk masing-masing type user (developer dan copywriter).
1class Developer < User2end
1class Copywriter < User2end
Kita akan mencoba meletakkan method association-nya pada model User dan juga model News.
1class User < ApplicationRecord2 has_many :news, dependent: :destroy3end
1class News < ApplicationRecord2 belongs_to :user3end
Kalau asosiasinya seperti di atas, maka user Developer juga dapat membuat News.
1irb(main)> user_developer = Developer.first2=> #<Developer id: 1, email: "bayuyuba@gmail.com", ...34irb(main)> user_developer.news5=> #<ActiveRecord::Associations::CollectionProxy []>
Sedangkan, yang kita inginkan adalah hanya user Copywriter yang dapat membuat News.
1irb(main)> user_copywriter = Copywriter.first2=> #<Copywriter id: 2, email: "bololoba@gmail.com", ...34irb(main)> user_copywriter.news5=> #<ActiveRecord::Associations::CollectionProxy []>
Developer juga dapat membuat News karena kita meletakkan association-nya pada model User (has_many :news
) dan pada model News (belongs_to :user
). Sedangkan pada model User, terdapat dua type user, yaitu Developer dan Copywriter. Tentu saja kedua type user tersebut jadi memiliki association terhadap model News.
Pemecahan Masalah
Sudah dapat ditebak yaa, seharusnya kita meletakkan associationnya pada model Copywriter, bukan pada model User.
Maka, kita perlu menghapus association yang ada pada model User dan memindahkannya ke model Copywriter.
1class Copywriter < User2 has_many :news, dependent: :destroy, foreign_key: :user_id3end
Sedangkan association pada model News kita akan ganti objectnya ke model Copywriter.
1class News < ApplicationRecord2 belongs_to :copywriter, foreign_key: :user_id3end
Yang menjadi kunci dari association antara model Copywriter dengan model News di atas adalah foreign_key: :user_id
.
Sangat perlu untuk didefinisikan, karena model News sebenarnya tidak mengetahui siapa itu Copywriter. Model News hanya mengenal User, nanti model User yang akan memberitahu, bahwa yang si News cari adalah salah satu type user yang dimiliki oleh model User, yaitu Copywriter. 😅
Hal ini karena secara skematik, pada tabel News, kita merelasikan dengan tabel Users. Sedangkan Copywriter tidak memiliki tabel.
1# ...23 create_table "news", force: :cascade do |t|4 t.string "title"5 t.bigint "user_id", null: false6 t.datetime "created_at", precision: 6, null: false7 t.datetime "updated_at", precision: 6, null: false8 t.index ["user_id"], name: "index_news_on_user_id"9 end1011# ...
Pengujian
Kita akan mulai dari Copywriter.
1irb(main)> user_copywriter = Copywriter.first2=> #<Copywriter id: 2, email: "bololoba@gmail.com", ...34irb(main)> user_copywriter.news5=> #<ActiveRecord::Associations::CollectionProxy []>
Nah, copywriter masih memiliki berasosiasi dengan model News.
Seharusnya model Developer, sudah tidak dapat membuat News.
1irb(main)> user_developer = Developer.first2=> #<Developer id: 1, email: "bayuyuba@gmail.com", ...34irb(main)> user_developer.news5NoMethodError (undefined method `news' for #<Developer id: 1, email: "bayuyuba@gmail.com", ...">)6
Oke, mantap! Developer sudah tidak dapat membuat News.
Pesan Penulis
Sepertinya, segini dulu yang dapat saya tuliskan.
Selanjutnya, saya serahkan kepada imajinasi dan kreatifitas teman-teman. Hehe.
Mudah-mudahan dapat bermanfaat.
Terima kasih.
(^_^)
Referensi
- guides.rubyonrails.org/association_basics.html#single-table-inheritance-sti
Diakses tanggal: 2021/02/17