Ruby on rails HABTM的使用有很多:通过-需要帮助确定我在哪里';我做错了

Ruby on rails HABTM的使用有很多:通过-需要帮助确定我在哪里';我做错了,ruby-on-rails,activerecord,associations,has-many,has-many-through,Ruby On Rails,Activerecord,Associations,Has Many,Has Many Through,大约一小时前,我问了一个关于rails关联的问题: 这个问题的公认答案让我更深入地思考人际关系,我想向SO社区介绍这种情况 我之前的问题以诗人、诗歌和印刷术为模型。。。对于这一点,让我们使用音乐行业: 这些模型是: 艺术家 相册 歌 体裁 以下陈述应视为真实: 一张专辑可以有多个艺术家——即Metallica和Pantera发行一张圣诞专辑 一首歌可以属于多张专辑-即黄色潜水艇在原始专辑以及披头士乐队的一些“最热门”专辑中 一首歌也可以有多个不同于专辑艺术家的“特色”艺术家——即斯努普·多

大约一小时前,我问了一个关于rails关联的问题:

这个问题的公认答案让我更深入地思考人际关系,我想向SO社区介绍这种情况

我之前的问题以诗人、诗歌和印刷术为模型。。。对于这一点,让我们使用音乐行业:

这些模型是:

  • 艺术家
  • 相册
  • 体裁
以下陈述应视为真实:

  • 一张专辑可以有多个艺术家——即Metallica和Pantera发行一张圣诞专辑
  • 一首歌可以属于多张专辑-即黄色潜水艇在原始专辑以及披头士乐队的一些“最热门”专辑中
  • 一首歌也可以有多个不同于专辑艺术家的“特色”艺术家——即斯努普·多格拥有这张专辑,但一首以小哈利·康尼克为主角的歌也可以,或者一个更好的例子是,当DJ发行一张专辑时,所有歌曲都是由其他艺术家创作的
  • 艺术家、专辑和歌曲都可以分为多种/不同的类型——即Brian Setzer交响乐团被归类为“Swing”,他们的一张专辑可以是“Swing,Rockabily”,专辑中的一首歌可以是“Jump Blues”
  • 当我深入研究这个问题时,我立刻发现像《艺术家与流派》这样的模型可以“重用”。我们不想多次保存艺术家的信息——因此,例如,在事件中,我们有一首歌,其中包括一位主要艺术家和一位特写艺术家,两位艺术家的信息都应该保存在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
    
    class-Artist:Featureings,:conditions=>“featured=true”
    结束
    类相册:特色,:条件=>“特色=真实”
    结束
    类歌曲:特色,:条件=>“特色=真实”
    结束
    类类型

    像往常一样,非常感谢那些花时间阅读并提供意见的人!非常感谢

    这与其说是一个问题,不如说是一个讨论,但我将尝试解决您的担忧。我没有测试你的任何代码,所以这些只是我的想法

    (Artist) has_any_belongs_to_many :genres
    
    你需要一张单独的桌子吗?信息已经通过歌曲和流派之间的关联存储。除非艺术家在没有上述流派歌曲的情况下也可以属于该流派,否则您不应在其他HABTM协会中复制此信息

    反之亦然,相反的关联可能是多余的:

    (Genre) has_any_belongs_to_many :artists
    
    至于特性方面的设计,将flag featured设置为true的特性似乎也是多余的。然而,这是因为命名,所以如果我是你,我会将其重命名为Release(歌曲可以在多张专辑中发布)。如果你认为特色标志存在于艺术家和歌曲之间,你应该将该标志添加到禁止实体中(忘记该术语)

    然而,由于其表达为HABTM关联,因此没有干预模型。因此,您必须将其转换为使用歌曲和艺术家上的HASU many,中间的模型包含“属于”关联以及特色标志。这实际上是发布模型

    这(同样没有进行测试)将您的模型简化为:

    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
    
    class-Artist:发行
    拥有多张:专辑,:至=>:发行版
    有很多:精选歌曲,通过=>:releases,:conditions=>“精选=true”
    结束
    类相册:发行
    有很多:艺术家,:至=>:发行
    结束
    类发布:发行
    拥有多张:专辑,:至=>:发行版
    通过=>:releases,:conditions=>“featured=true”,拥有\u many:featured\u艺术家
    结束
    类类型
    我不是HABTM协会的粉丝。所以我用了很多联想。为了解决属于专辑、歌曲等的流派,我使用了多态关联。解决方案相当复杂。但它满足了所有要求:

    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\u 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
    
    song1.featured_artists << artist2 
    
    song1.featured_artist_links.create(:featured => true, :artist => artist2)