Raylar aynı modeli ile çok-çok ilişki?
Nasıl raylar aynı modeli ile çok-çok ilişki yapabilir miyim?
Örneğin, her yazı birçok mesaj bağlanır.
CEVAP
Çok-çok ilişkileri vardır; kendinize şu soruları sormak gerekir:
- Dernek ek bilgi depolamak istiyor muyum? (Ek tablo alanlar katılabilir.)
- Dernekler örtülü olarak iki yönlü olması gerekiyor mu? (Eğer yazı Bir B post bağlıysa, o zaman yazı B de direğe bağlanır A.)
Dört farklı olasılık kalıyor. Bu aşağıda üzerinde yürüyeceğim.
Başvuru için: the Rails documentation on the subject. Bir bölüm var, adı “çok-Çok”, ve tabii ki sınıf yöntemleri belgelerine kendilerini.
Basit bir senaryo, tek yönlü, hiçbir ek alanlar
Bu kodu en kompakt.
Yazılarınız için bu temel şema ile başlarım
create_table "posts", :force => true do |t|
t.string "name", :null => false
end
Çok-çok ilişki için bir masaya ihtiyacın var. İşte bunun için: şema
create_table "post_connections", :force => true, :id => false do |t|
t.integer "post_a_id", :null => false
t.integer "post_b_id", :null => false
end
Varsayılan olarak, Raylar bu tablo katılıyoruz iki tablo isimlerini bir arada arar. Ama o post_connections
yerine almaya karar verdim, bu durumda posts_posts
olarak ortaya çıkmaktadır.
Burada çok önemli id
sütun varsayılan atlamak için :id => false
,. Raylar bu sütun her yerde istiyorhariçkatılmak tablolar has_and_belongs_to_many
için. Yüksek sesle şikayet edecek.
Son olarak, sütun adlarını standart olmayan (post_id
), çatışmayı önlemek için dikkat edin.
Şimdi bu model, sadece Raylar standart olmayan şeyler hakkında bu birkaç söylemek gerekir. Aşağıdaki gibi görünecektir
class Post < ActiveRecord::Base
has_and_belongs_to_many(:posts,
:join_table => "post_connections",
:foreign_key => "post_a_id",
:association_foreign_key => "post_b_id")
end
Ve bu sadece iş! İşte örnek bir ırb oturum script/console
ile çalıştırın:
>> a = Post.create :name => 'First post!'
=> #<Post id: 1, name: "First post!">
>> b = Post.create :name => 'Second post?'
=> #<Post id: 2, name: "Second post?">
>> c = Post.create :name => 'Definitely the third post.'
=> #<Post id: 3, name: "Definitely the third post.">
>> a.posts = [b, c]
=> [#<Post id: 2, name: "Second post?">, #<Post id: 3, name: "Definitely the third post.">]
>> b.posts
=> []
>> b.posts = [a]
=> [#<Post id: 1, name: "First post!">]
posts
dernek için atama uygun olarak post_connections
tablodaki kayıtları yaratacak bulabilirsiniz.
Bazı şeyler için not:
- Dernek, tek yönlü olduğunu yukarıda ırb oturumda gördüğünüz gibi, ilk yazı içermez
a.posts = [b, c]
, çünkü sonra. - Fark etmişsinizdir başka bir şey 27* *hiçbir model yoktur. Normalde
has_and_belongs_to_many
bir dernek için modeller kullanma. Bu nedenle, herhangi bir ek alanlar erişmek mümkün olmayacaktır.
Tek yönlü, ek alanlar ile
Şimdi... bugün yılan balığı çok lezzetli hakkında sitenizde bir post yapmış düzenli bir kullanıcı var. Yabancı bir adam etrafında site, belirtileri gelir ve normal bir kullanıcı beceriksizliği üzerine azarlar bir yazı yazar. Sonuçta, yılan balıklarının nesli tükeniyor!
Post A. bunu yapmak İçin yazılan B azarlar bir rant veritabanınızdaki açıklığa kavuşturmak istiyorum, Derneği category
bir alan eklemek istiyorum.
İhtiyacımız olan şey artık has_and_belongs_to_many
amahas_many
, belongs_to
, has_many ..., :through => ...
ve ekstra bir model bir kombinasyon için birleştirme bir tablo. Bu ekstra model Amerikan Derneği kendisi için ek bilgi eklemek için güç verir.
Burada başka bir şema, yukarıda çok benzer:
create_table "posts", :force => true do |t|
t.string "name", :null => false
end
create_table "post_connections", :force => true do |t|
t.integer "post_a_id", :null => false
t.integer "post_b_id", :null => false
t.string "category"
end
Nasıl, bu durumda, post_connections
dikkat edinyokid
bir sütun var. (Varhayır:id => false
parametre.) Bu tablo erişmek için düzenli ActiveRecord bir model olacak çünkü gerekli.
Ölü basit çünkü PostConnection
model ile başlayacağım:
class PostConnection < ActiveRecord::Base
belongs_to :post_a, :class_name => :Post
belongs_to :post_b, :class_name => :Post
end
Tek şey burada Raylar burada bir görev ile karşı karşıyayız post_a
post_b
ikna edemiyor çünkü gerekli olan :class_name
. Bunu açıkça söylemek zorundayız.
Şimdi Post
model:
class Post < ActiveRecord::Base
has_many :post_connections, :foreign_key => :post_a_id
has_many :posts, :through => :post_connections, :source => :post_b
end
has_many
ilk Derneği ile model posts.id = post_connections.post_a_id
46 *katılmak için söylüyoruz.
İkinci dernek, biz anlatmaya Raylar o ulaşabileceğimiz diğer mesajlar, bağlı olanlar için bu, bizim ilk Derneği post_connections
ardından post_b
Derneği PostConnection
.
Sadece oradabir şey daha vareksik ve o PostConnection
a ait mesaj bağımlı olan Raylar anlatmalıyız. post_a_id
post_b_id
biri veya her ikisi de bağlantı pek bir şey olmaz o zaman 54 ** olsaydı, değil mi? Post
modelimiz bu işi böyle yapacağız:
class Post < ActiveRecord::Base
has_many(:post_connections, :foreign_key => :post_a_id, :dependent => :destroy)
has_many(:reverse_post_connections, :class_name => :PostConnection,
:foreign_key => :post_b_id, :dependent => :destroy)
has_many :posts, :through => :post_connections, :source => :post_b
end
Sözdizimi ufak bir değişiklik dışında, iki gerçek burada işler farklı
has_many :post_connections
58 *fazladan bir parametre vardır. Değeri ile:destroy
bu yazı kaybolur sonra, devam edin ve bu nesneleri yok edebilir, bu Raylar söylüyoruz. İşte kullanabileceğiniz alternatif bir değer daha hızlı olan:delete_all
, ama eğer varsa o kullanıyorsanız kanca yok.- İçin
has_many
bir dernek eklediktersbağlantıları da, bize bağlı olanlarpost_b_id
. Bu yol, Raylar düzgün o da yok edebilir. Model sınıf adı artık:reverse_post_connections
olayla olabilir çünkü:class_name
burada belirtmek zorunda olduğumuzu unutmayın.
Bu, script/console
başka bir ırb oturum getirdim:
>> a = Post.create :name => 'Eels are delicious!'
=> #<Post id: 16, name: "Eels are delicious!">
>> b = Post.create :name => 'You insensitive cloth!'
=> #<Post id: 17, name: "You insensitive cloth!">
>> b.posts = [a]
=> [#<Post id: 16, name: "Eels are delicious!">]
>> b.post_connections
=> [#<PostConnection id: 3, post_a_id: 17, post_b_id: 16, category: nil>]
>> connection = b.post_connections[0]
=> #<PostConnection id: 3, post_a_id: 17, post_b_id: 16, category: nil>
>> connection.category = "scolding"
=> "scolding"
>> connection.save!
=> true
Dernek oluşturma ve daha sonra ayrı ayrı kategori ayarı yerine, sadece bir PostConnection oluşturmak ve bu iş biter
>> b.posts = []
=> []
>> PostConnection.create(
?> :post_a => b, :post_b => a,
?> :category => "scolding"
>> )
=> #<PostConnection id: 5, post_a_id: 17, post_b_id: 16, category: "scolding">
>> b.posts(true) # 'true' means force a reload
=> [#<Post id: 16, name: "Eels are delicious!">]
Ve aynı zamanda post_connections
reverse_post_connections
dernekler kullanabiliriz; düzgün posts
dernek yansıtacak:
>> a.reverse_post_connections
=> #<PostConnection id: 5, post_a_id: 17, post_b_id: 16, category: "scolding">
>> a.reverse_post_connections = []
=> []
>> b.posts(true) # 'true' means force a reload
=> []
Çift yönlü dernekler döngüye
has_and_belongs_to_many
normal dernekler, dernek tanımlanırher ikisi demodelleri dahil. Dernek çift yönlüdür.
Ama bu durumda tek bir Yazı modeli var. Dernek sadece bir kez belirtildi. Bu özel durumda, dernekler, tek yönlü olan tam da bu yüzden.
Aynı has_many
ve bir model ile alternatif yöntem tablo katılmak için de geçerlidir.
Bu sadece ırb gelen dernekler erişme ve Raylar günlük dosyası oluşturur SQL bakıldığında en iyi görülür. Aşağıdaki gibi bir şey göreceksiniz:
SELECT * FROM "posts"
INNER JOIN "post_connections" ON "posts".id = "post_connections".post_b_id
WHERE ("post_connections".post_a_id = 1 )
Yapmak dernek çift yönlü, yapmak zorundayız bulmak için bir yol Rayları OR
yukarıdaki koşulları post_a_id
post_b_id
tersine, çok daha kolay olacak bak iki taraftan da.
Ne yazık ki, ben biliyorum ki bunu yapmak için tek yol oldukça hacky. El ile SQL*,* 80 ** 79, vb gibi has_and_belongs_to_many
seçenekleri kullanarak belirtmek gerekiyor. Hoş bir şey değil. (Öneriler burada açık da değilim. Kimse?)
Nasıl açıkça bir Modeli'Raylar ta...
Nasıl otomatik olarak Raylar has_many ...
3, nasıl dinlenme uygulaması olarak ay...
Büyük / küçük harf duyarlı Raylar aram...
Nasıl ActiveRecord modeli ve Raylar ta...