Rails – Active Record – Model İlişkileri – 3

Çoktan Çoğa İlişkilerin Oluşturulması

Category ve Article isminde iki modelimiz olsun. Article modelinin herhangi bir nesnesinin birden çok Category’ye ait olduğu, aynı zamanda kategori nesnesinin birden çok Article nesnesini içerdiği durumlar çoktan çoğa ilişkiye, yani has_and_belongs_to_many durumuna örnek olabilir.

has_and_belongs_to_many ilişkisi, referans foreign key’leri tutan bir “join table” yani birleştirme tablosu ile birlikte çalışır. Birleştirme tablosu, birleştirilmek istenen iki tablo arasında – yani mevcut durumda “articles” ve “categories” arasında bulunur.

Birleştirme tablosu konvansiyonel olarak, birleştirilecek tabloların isimlerinin alfabetik sırayla ve alt çizgi ile birleştirilmesinden oluşur. O halde mevcut durum için birleştirme tablosunun ismi “articles_categories” olacaktır.

has_and_belongs_to_many
Görselde bir hata var, normalde join tablosunun adı articles_categories‘tir.

Öncelikle Category modelini oluşturalım:

Ardından join table’ı, yani birleştirme tablomuzu oluşturalım:

Normal şartlar altında primary key’ler migration sırasında otomatik olarak oluşur. Ancak birleştirme tablolarında primary key’e ihtiyacımız olmadığı için, migration dosyasında bu durumun  :id => false ile belirtilmesi gereklidir ki primary key oluşturulmasın:

t.references :article;

şeklinde de kullanılabilirdi. Veritabanımızı migrate edelim:

Şimdi ise model dosyalarımızı bu kurduğumuz ilişkiden haberdar edelim:

article.rb
category.rb

Seeding Data

Uygulama iskeletini oluştururken devamlı olarak ihtiyaç duyacağımız verileri, veritabanına eklenmek üzere hazır tutan “db/seeds.rb” dosyası her Rails uygulamasında varsayılan olarak bulunur. Bazı kategorilerin ve kullanıcıların otomatik olarak oluşturması için dosyayı düzenleyelim:

DB’yi seed edelim:

Eğer ileride daha çok kategori eklememiz gerekirse seed dosyasına bunlarıda ekleyip rake task’i tekrar çalıştırabiliriz ancak bunu yaparken, seeds dosyasının verilerin varolup olmadığına dair bir kontol içermediğini unutmamak gerekir. Yani bir başka değişle, rake db:seed‘i her çalıştırdığımızda, seed dosyası içerisindeki veriler veritabanında tekrar oluşturulur. Bunun bir sonucu olarak bir çok duplicate veri ile karşılabilirsiniz. Bu durumun oluşmaması için;

çalıştırabilirsiniz. Bu rake task çalıştırıldığı zaman veritabanını sıfırdan tekrar oluşturur ve seed dosyasındaki verileri veritabanına ekler. Yaptığımız işlemleri kısaca test edelim:

Gördüğünüz gibi category ve article’ı “<<” operatörü aracılığı ile ilişkilendirdik. Yukarıda ki işlemleri, ilişkinin diğer tarafından, yani cateogry üzerinden de gerçekleştirebilirdik çünkü has_and_belongs_to_many ilişkisi çift taraflı çalışır.

Çoktan çoğa ilişkilerde, has_and_belongs_to_many hem kurulması çok kolay hemde kullanışlı bir ilişki türüdür. Ancak kurduğumuz has_and_belongs_to_many ilişkisinin join table’ında, ilişkili tablolardan gelen ID’ler dışında başka hiç bir veri tutulamadığından ve ortada join table’a ait bir model bulunmadığı için bu ilişki türü bazen yeterli gelmeyebilir.

Örneğin article ile category’nin ne zaman ilişkilendirildiğini tutan bir timestamp alanı oluşturmak veya bu ilişkiyi kuran user’ın IP adresini saklamak istesek bunun için en uygun yer şüphesiz join table olacaktır. Ancak ortada join table’a ait bir model bulunmadığı için bunlar gibi çeşitli bilgileri tutmamız mümkün değildir. Bu gibi verileri tutabileceğimiz, kendi modeli olan ve join table’ı primary key içeren çoktan çoğa ilişkileri ise has_many :through ile kurabiliriz.

Çoktan Çoğa Zengin İlişkilerin Oluşturulması

Bu ilişki türünün temel özelliği; kurulan ilişki verilerinin tutan join table için komple (primary key’e sahip) bir model oluşturulmasıdır.

Örnek uygulamamızdan yola çıkarak planlayacak olursak; normalde article’lar pek çok yoruma sahip olabilir ve biz bunu sağlamak için ilk önce comment modelimizi oluştururuz. Ardından ise bu iki modelin (comment ve article), arasında has_many ve belongs_to ikilisiyle bire-bir ilişki kurarız. Peki bir user’ın article’ına yazılmış olan tüm yorumları bulmak istesek? Buna benzer bir ilişkiyi aşağıdaki gibi kurarız:

rich_many_to_many

Comment” modelimiz için modeli ve migration’ı oluşturalım:

DB’yi migrate edelim:

Modellerimizi kurduğumuz ilişkiye göre düzenleyelim:

article.rb
comment.rb

Aslında burada kurduğumuz ilişki daha önceden kurduğumuz users-articles ilişkisi ile aynı. Aradaki fark ise bu durumda, user’ın birden çok article’a sahip olması değil – article’ın birden çok comment’e sahip olması.

Kurmaya çalıştığımız users-comments ilişkisine geri dönelim. User modeline; “bir user – articles üzerinden birden çok comment’e sahiptir” ilişkisini tanıtmak için User modelimizi düzenleyelim:

Kurduğumuz ilişkiyi console’dan test edelim:

Leave a Reply