2010-07-21 62 views
1

我有用户,游戏和GameView。 GameView描述了用户看到的游戏。麻烦是我无法弄清楚我应该使用什么条件来获取未观看的游戏。has_many“不是”:通过。我应该使用什么条件?

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 

回答

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应该缓存,但叫我偏执狂。

希望这有助于!

+0

+1。不需要在查询中添加':include'子句。我也会删除声明检查行,即'@unviewed_games || = Game.all(...' – 2010-07-21 07:05:07

+0

关于':include'的好声音,我在写邮件时改变了查询。 ,只是因为'|| ='仍然可以重新查询数据库,如果一个零返回 - 不应该发生在'.all'上,但我喜欢我的代码是一致的。这样我总是有声明检查而不是有时'|| ='有时候还有一个声明检查。 – 2010-07-21 15:46:44

0

为什么你不has_many:viewing_games并写一个单独的方法来收集未经审查的游戏?我会犹豫在has_many中添加更多逻辑。

0

你不能在Rails中用这种方式表达关系,使用has_many :through(或者至少不是我所知)。但是,您可以基于:game_views创建一个命名范围以检索所需的对象。

我相信这将做的伎俩(未测试):

named_scope :unviewed_games, :joins => 'LEFT JOIN game_views ON game_views.game_id = games.id', :conditions => 'game_view_id IS NULL')

相关问题