大约一小时前,我问了关于轨道协会的问题:
Question on Proper Associations in Rails
这个问题的公认答案让我更深入地思考了人际关系,我想向SO社区介绍这种情况。
我之前的问题使用诗人,诗歌和印刷作为模型......对于这一个让我们使用音乐产业:
模型是:
以下陈述应被视为真实:
在深入研究这个问题时,我立即看到了诸如Artist& amp;类型可以“重用”。我们不想多次保存艺术家的信息 - 例如,如果我们有一首主要艺术家和特色艺术家的歌曲,艺术家的信息应该存在于DB的“艺术家”表中。
此外,在查看“特色”艺术家方面(声明#2)时,似乎我们还有一个应该在关联上的附加属性 - 类似于“特色”标志。
以下是我认为应该如何设置关联 - 以及我的帖子的顶点....这是正确的,我怎样才能让它变得更好?
class Artist < ActiveRecord::Base
has_and_belongs_to_many :albums
has_and_belongs_to_many :genres
has_many :featurings
has_many :features, :through => :featurings, :conditions => "featured = true"
end
class Album < ActiveRecord::Base
has_and_belongs_to_many :artists
has_and_belongs_to_many :songs
has_many :featurings
has_many :featured_artists, :through => :featurings, :conditions => "featured = true"
end
class Song < ActiveRecord::Base
has_and_belongs_to_many :genres
has_many :artists
has_many :featurings
has_many :featured_artists, :through => :featurings, :conditions => "featured = true"
end
class Genre < ActiveRecord::Base
has_and_belongs_to_many :artists
has_and_belongs_to_many :songs
end
class Featurings < ActiveRecord::Base
# the db table for this class should have a "featured" boolean.
belongs_to :artist
belongs_to :album
belongs_to :song
end
像往常一样,非常感谢那些花时间阅读和提供意见的人!非常感谢!
答案 0 :(得分:5)
这不是一个讨论而是一个问题,但我会尝试解决你的问题。我没有测试你的任何代码,所以这些只是我的想法。
(Artist) has_any_belongs_to_many :genres
你需要一个单独的表吗?信息已经通过歌曲和流派之间的关联存储。除非艺术家可以属于流派,尽管没有所述类型的歌曲,否则你不应该在另一个HABTM协会中重现这些信息。
反之亦然,相反的关联可能是多余的:
(Genre) has_any_belongs_to_many :artists
至于你的特色方面的设计,似乎有一个功能设置为true的功能也是多余的。但是,这是因为命名,所以如果我是你,我会将它重命名为Release(歌曲可以在多个专辑中发布)。如果您认为艺术家和歌曲之间存在特色标志,您应该将标志添加到禁止实体(忘记了这个术语)。
然而,由于它表示为HABTM关联,因此没有介入模型。因此,您必须将此转换为在Song和Artist上使用has_many,其中插入的模型包含belongs_to关联以及特征标志。这实际上是发布模型。
这(再次没有进行过测试)将模型缩减为:
class Artist < ActiveRecord::Base
has_and_belongs_to_many :albums
has_many :releases
has_many :songs, :through => :releases
has_many :albums, :through => :releases
has_many :featured_songs, through => :releases, :conditions => "featured = true"
end
class Album < ActiveRecord::Base
has_and_belongs_to_many :artists
has_many :releases
has_many :songs, :through => :releases
has_many :artists, :through => :releases
end
class Release < ActiveRecord::Base
belongs_to :artist
belongs_to :song
belongs_to :album
# there should be a featured boolean
end
class Song < ActiveRecord::Base
has_and_belongs_to_many :genres
has_many :releases
has_many :artists, :through => :releases
has_many :albums, :through => :releases
has_many :featured_artists, through => :releases, :conditions => "featured = true"
end
class Genre < ActiveRecord::Base
has_and_belongs_to_many :songs
end
答案 1 :(得分:2)
我不是HABTM协会的粉丝。所以我使用了has_many关联。为了解决属于专辑,歌曲等的类型,我使用了多态关联。解决方案非常复杂。但它满足了所有要求:
class Artist
has_many :genre_links, :as => :genre_holder
has_many :genres, :through => :genre_links
has_many :artist_links
has_many :albums, :through => :artist_links,
:source => :artist_holder, :source_type => "Album"
has_many :songs, :through => :artist_links,
:source => :artist_holder, :source_type => "Song"
has_many :featured_songs, :through => :artist_links,
:source => :artist_holder, :source_type => "Song",
:conditions => {:featured => true}
end
使用:source_type
选项为相册和歌曲创建关联。
class Genre
has_many :genre_links
has_many :albums, :through => :genre_links,
:source => :genre_holder, :source_type => "Album"
has_many :songs, :through => :genre_links,
:source => :genre_holder, :source_type => "Song"
end
class GenreLink
belongs_to :genre_holder, :polymorphic => true
belongs_to :genre
end
class ArtistLink
# featured
belongs_to :artist
belongs_to :artist_holder, :polymorphic => true
end
我们需要一个自定义SQL来获取专辑的精选歌曲。
class Album < ActiveRecord::Base
has_many :genre_links, :as => :genre_holder
has_many :genres, :through => :genre_links
has_many :artist_links, :as => :artist_holder,
:condition => {:featured => false}
has_many :artists, :through => :artist_links
has_many :album_songs
has_many :songs, :through => :album_songs
has_many :featured_artists, :class => "Artist", :custom_sql => '
SELECT A.* FROM artists A WHERE A.id IN (
SELECT DISTINCT B.artist_id FROM artist_links B
WHERE B.artist_holder_type = "Song" AND B.featured = 1 AND
B.artist_holder_id IN (#{song_ids.join(",")}))'
end
现在剩下的课程了:
class AlbumSong
belongs_to :album
belongs_to :song
end
class Song < ActiveRecord::Base
has_many :genre_links, :as => :genre_holder
has_many :genres, :through => :genre_links
has_many :album_songs
has_many :albums, :through => :album_songs
has_many :artist_links, :as => :artist_holder,
:condition => {:featured => :false}
has_many :artists, :through => :artist_links
has_many :featured_artist_links, :class => "ArtistLink",
:as => :artist_holder, :condition => {:featured => :true }
has_many :featured_artists, :through => :featured_artist_links,
:source => :artist
end
艺术家可以与专辑和/或歌曲相关联。
album1.artists << artist1
song1.artists << artist1
将歌曲标记为精选:
Rails 3
song1.featured_artists << artist2
Rails在创建期间自动设置关联的哈希条件参数。所以别无他法。
Rails 2.x
song1.featured_artist_links.create(:featured => true, :artist => artist2)