很抱歉,如果标题不清楚,我不知道如何更好地说出来。
我有一个模型“播放列表”,其中has_many和belongs_to另一个模型“用户”,通过中间模型“PlaylistUser”。
假设我在给定播放列表(@playlist
)和@users = @playlist.users
的页面上。如何列出所有其他播放列表,按照与@playlist
分享的用户数排序?
因此,如果@playlist.users = ["joe","nick","bob"]
,<playlist2>.users = ["nick","bob","tom"]
和<playlist 3>.users = ["bob","jim","rich"]
,则应首先列出播放列表2,因为它与@playlist
共享2个用户,而播放列表3仅共享1个用户。
我希望我做了我想做的事情,但是如果需要进一步说明,请告诉我。
关联设定:
class Playlist < ActiveRecord::Base
has_many :playlist_users
has_many :users, :through => :playlist_users
end
class PlaylistUser < ActiveRecord::Base
belongs_to :playlist
belongs_to :user
end
class User < ActiveRecord::Base
has_many :playlist_users
has_many :playlists, :through => :playlist_users
end
答案 0 :(得分:1)
这将简化您的模型。您已经确定了&#34;拥有并属于许多&#34;关系,这是如何实现它。
首先,您只需要两个型号。播放列表和用户
class Playlist < ActiveRecord::Base
has_and_belongs_to_many :users
end
class User < ActiveRecord::Base
has_and_belongs_to_many :playlists
end
接下来你需要3张桌子。
class SampleMigration < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
end
create_table :playlists do |t|
t.string :name
end
create_table :playlists_users, id: false do |t|
t.belongs_to :playlist
t.belongs_to :user
end
end
end
请注意,复数在命名集合中很重要,例如has_and_belongs_to_many :users
以及表格create_table :users
的名称。
连接表不需要模型,但需要按字母顺序命名,名称复数。
现在,您可以使用user.playlists
返回与此用户相关联的播放列表数组。作为一个数组,您可以拨打user.playlists[5]
来获取列表中的第5首歌曲,或者您可以对其进行迭代user.playlists.each do |list|
。
所以,如果@ playlist.users = [&#34; joe&#34;,&#34; nick&#34;,&#34; bob&#34;],。users = [&#34; nick&#34 ;&#34; bob&#34;,&#34; tom&#34;]和.users = [&#34; bob&#34;,&#34; jim&#34;,&#34; rich&#34 ;],首先应列出playlist2,因为它与@playlist共享2个用户,而playlist3仅共享1个用户。
有两种方法可以实现这一目标。通过一个帮助方法,您可以在其中检索所有列表并在Rails中或通过SQL查询将它们联合起来。 SQL更快,但需要SQL知识。最初我会使用Rails并在获得收益时处理SQl。
一个实现可能是(注意:将其视为伪代码,我还没有对其进行测试);
# get all the lists
newPlaylist = array.new
users = @playlist.users
users.each do |user|
newPlaylist = newPlaylist + user.playlists
end
# count all the lists
countPlaylists = Hash.new
newPlaylist.each do |list|
if list.in? countPlaylists.keys
countPlaylists[list] = countPlaylists[list] + 1
else
countPlaylists[list] = 1
end
end
# sort the list - I'm not sure if it sorts on keys or values,
# but either way you should be able to figure it out
countPlaylists.sort
答案 1 :(得分:1)
Playlist.joins(:users)
.where.not(id: @playlist.id)
.where(users: {id: @playlist.user_ids})
.group(:id)
.order('count(*) desc')
或者,如果您需要访问count(*)的结果:
@playlists = Playlist.select('playlists.*, count(*) as shared_users_count')
.joins(...)
...
.order('shared_users_count desc')
# print out shared users count
@playlists.each { |pl| puts pl.shared_users_count }