has_many“不是什么”:通过。我应该使用什么条件?

时间:2010-07-21 05:40:51

标签: ruby-on-rails

我有用户,游戏和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

3 个答案:

答案 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')