开发者

has_many "not something" :through. What conditions should I use?

开发者 https://www.devze.com 2023-01-08 17:32 出处:网络
I have User, Game and GameView. GameView describe what games users have seen. Trouble is I can\'t figure out 开发者_如何转开发what conditions should I use to fetch unviewed games.

I have User, Game and GameView. GameView describe what games users have seen. Trouble is I can't figure out 开发者_如何转开发what conditions should I use to fetch unviewed games.

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


I don't see this as an association because an association is generally something where you have a foreign key pointing to something, but in this case you have no foreign key. I see this as more of an instance attribute which I would do like this:

def unviewed_games
  Game.all(:conditions => ["id NOT IN (SELECT game_id FROM game_views WHERE user_id = ?", self.id])
end

You could do a NOT IN (1,2,3) by querying the viewed games, but that can get very inefficient, very very fast. This is one time I would write out the SQL. I would also do one more thing:

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

That will store it in an instance variable for the length of the request, and save you the multiple database hits. You can do ||=, but if somehow you were to get a nil, then you would still query the database multiple times. Rails should cache, but call me paranoid.

Hope this helps!


Why don't you has_many :viewed_games and write a separate method to collect unviewed games? I'd be hesitant to put any more logic in a has_many.


You can't express a relationship this way in Rails using has_many :through (or at least not to my knowledge). But you can create a named scope based on :game_views to retrieve the desired objects.

I believe this will do the trick (not tested):

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

0

精彩评论

暂无评论...
验证码 换一张
取 消