【问题标题】:Rails Modeling Question - Relationships and Primary KeysRails 建模问题 - 关系和主键
【发布时间】:2009-11-05 22:55:44
【问题描述】:

我正在开发一个我继承的 Rails 网站,并试图解决一些次优模型行为。我有用户、歌曲和歌曲下载,每个都是自己的模型。

这是用户模型中的相关行:

has_and_belongs_to_many :downloaded_songs, :class_name => 'Song', :join_table => :song_downloads

来自歌曲模型:

has_and_belongs_to_many :downloaded_users, :class_name => 'User', :join_table => :song_downloads

来自 song_downloads 模型:

belongs_to :user
belongs_to :song

这是在用户下载歌曲时(在歌曲控制器中)创建新 song_download 记录的代码:

SongDownload.create( :song_id => @song.id,
                     :user_id => current_user.id,
                     :download_date => Date.today )

我遇到的问题是,一旦用户下载了一首歌曲,如果我尝试从交互式控制台调用下载的用户,例如,键入以下内容:

Song.find(<some id>).downloaded_users

我取回了用户的完整记录,但是返回的objected中的id是SongDownload的主键,而不是User的主键。所有其他字段都是准确的,但 ID 不准确。

我没有提出这个建模方案,在我看来:has_and_belongs_to_many 可能更适合在没有明确建模的 SongDownload 对象的情况下使用,但如果我能提供帮助,我宁愿不彻底检查代码库。考虑到当前的建模方案,有什么方法可以取回正确的用户 ID?

非常感谢您的时间和考虑!

贾斯汀

【问题讨论】:

    标签: ruby-on-rails ruby database model


    【解决方案1】:

    Has 和 belongs to 关系正在逐步淘汰,取而代之的是 has many :through 关系。

    从好的方面来说,您不需要更改任何底层结构,只需更改 Song 和 User 模型中的关系声明。

    class Song < ActiveRecord::Base
    
      has_many :song_downloads
      has_many :users, :through => :song_downloads
    
      ...
    end
    
    class User < ActiveRecord::Base
    
      has_many :song_downloads
      has_many :songs, :through => :song_downloads
    
      ...
    end
    

    现在

    Song.find(<some id>).users
    

    返回通过 song_downloads 表连接到所选歌曲的用户对象数组。

    【讨论】:

    • 最重要的是,应该实施您的建议,因为无论如何,habtm 关系都是丑陋且非标准的。走 hmt 关系,一石二鸟。
    • 这样做是值得的。
    • EmFi,谢谢!到目前为止,一切都很好——你的建议已经到位。只有一件事:每当我执行Song.find(&lt;some id&gt;).downloaded_users 时,我会返回一组关联,而不是一组用户对象。如何获取用户数组?
    • 对不起,命令应该是Song.find(&lt;some id&gt;).users。另外,更改后@song.downloaded_users 不应该做任何事情。
    • 感谢您的回复!嗯...问题是,我有多个歌曲用户关系,因为用户也可以(例如)被通知新歌曲的发布(例如通过 notify_users)。如何在 Song.find().users 中指定歌曲用户关系的性质?
    【解决方案2】:

    当连接表的列多于两个外键时,建议使用 has_many :through。

    class User < ActiveRecord::Base
      has_many :song_downloads
      has_many :downloaded_songs,
               :through => :song_downloads,
               :source => :song
    end
    class Song < ActiveRecord::Base
      has_many :song_downloads
      has_many :downloaded_users,
               :through => :song_downloads,
               :source => :user
    end
    

    现在您可以获得下载过特定歌曲的用户列表,如下所示:

    Song.find(1).downloaded_users
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-25
      • 2014-01-31
      • 1970-01-01
      • 2015-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多