我有用户,游戏和GameView。 GameView描述了用户看过的游戏。麻烦的是我无法弄清楚我应该用什么条件来获取未经审核的游戏。
class User < ActiveRecord::Base
has_many :game_views
has_many :unviewed_games, :through => :game_views, :source => :game, ???what conditions???
end
class GameView < ActiveRecord::Base
belongs_to :user
belongs_to :game
end
答案 0 :(得分:1)
我不认为这是一个关联,因为一个关联通常是你有一个指向某个东西的外键,但在这种情况下你没有外键。我认为这更像是一个实例属性,我会这样做:
def unviewed_games
Game.all(:conditions => ["id NOT IN (SELECT game_id FROM game_views WHERE user_id = ?", self.id])
end
您可以通过查询已查看的游戏来执行NOT IN (1,2,3)
,但这可能会非常低效,速度非常快。这是我写出SQL的一次。我还会做一件事:
def unviewed_games
return @unviewed_games if defined(@unviewed_games)
@unviewed_games = Game.all(:conditions => ["id NOT IN (SELECT game_id FROM game_views WHERE user_id = ?", self.id])
end
这会将它存储在请求长度的实例变量中,并保存多个数据库命中。您可以执行||=
,但如果以某种方式获得nil
,那么您仍会多次查询数据库。 Rails应该缓存,但称我为偏执狂。
希望这有帮助!
答案 1 :(得分:0)
你为什么不has_many:seen_games并写一个单独的方法来收集未经审查的游戏?我会犹豫是否要在has_many中添加更多逻辑。
答案 2 :(得分:0)
你无法使用has_many :through
(或至少不是我所知)在Rails中以这种方式表达关系。但是您可以基于:game_views
创建命名范围以检索所需的对象。
我相信这会解决问题(未经测试):
named_scope :unviewed_games, :joins => 'LEFT JOIN game_views ON game_views.game_id = games.id', :conditions => 'game_view_id IS NULL')