【发布时间】:2012-01-31 11:03:37
【问题描述】:
我有 3 个模型
class Battle < ActiveRecord::Base
has_many :battle_videos
has_many :videos, :through => :battle_videos
...
end
class BattleVideo < ActiveRecord::Base
belongs_to :battle
belongs_to :video
validates :code, :presence => true
end
class Video < ActiveRecord::Base
belongs_to :user, :foreign_key => :user_id, :class_name => "User"
...
end
BattleVideo 有属性“code”(left_side || right_side),它决定了 BATTLE SIDE(战斗中总是有 2 个边,因为总是在玩 - 1 vs. 1,team vs. team 等等)
我想在模型 video 中指定关联 (left_side_video, right_side_video),它会获取所选一侧的视频。
现在获取 SIDE 1(左)的视频 - 使用此代码
Battle.first.battle_videos.where("battle_videos.code = 'left_side'").first.video
我想要这样的战斗视频
Battle.first.left_side_video
我认为,战斗模型应该是这样的,但它不起作用(只在左侧起作用)
class Battle < ActiveRecord::Base
has_many :battle_videos
has_many :videos, :through => :battle_videos
has_many :left_side_video, :through => :battle_videos, :source => :video, :conditions => ["battle_videos.code = 'left_side'"]
has_many :right_side_video, :through => :battle_videos, :source => :video, :conditions => ["battle_videos.code = 'right_side'"]
end
更新:
工作,但不是以期望的方式。问题出在includes 链中。
模型Battle 具有作用域:all_inclusive,它会加载所有关联
scope :all_inclusive, includes(:battle_category).includes(:bets).includes(:votes).includes(:left_side_video).includes(:right_side_video)
生成的 SQL:
Battle Load (0.6ms) SELECT `battles`.* FROM `battles` WHERE (battles.status = 1 AND valid_from < '2012-01-31 13:31:50' AND battles.valid_to > '2012-01-31 13:31:50') ORDER BY battles.id DESC
BattleCategory Load (0.1ms) SELECT `battle_categories`.* FROM `battle_categories` WHERE `battle_categories`.`id` IN (1)
Bet Load (0.1ms) SELECT `bets`.* FROM `bets` WHERE `bets`.`parent_type` = 'Battle' AND `bets`.`parent_id` IN (1, 2)
Vote Load (0.2ms) SELECT `votes`.* FROM `votes` WHERE `votes`.`parent_type` = 'Battle' AND `votes`.`parent_id` IN (1, 2)
BattleVideo Load (0.1ms) SELECT `battle_videos`.* FROM `battle_videos` WHERE `battle_videos`.`battle_id` IN (1, 2) AND (battle_videos.code = 'user_1')
Video Load (0.1ms) SELECT `videos`.* FROM `videos` WHERE `videos`.`id` IN (1, 3)
请注意,视频 2 和 4(右侧) - 不要加载。我只能访问 1,3 个视频
视频 id,battle_id(边)
[1 , 1 (lft)]
[2 , 1 (rgt)]
[3 , 2 (lft)]
[4 , 2 (rgt)]
当我从 :all_inclusive 链中删除 .includes(:right_side_video) 时,我得到了这个 sql:
Battle Load (0.6ms) SELECT `battles`.* FROM `battles` WHERE (battles.status = 1 AND valid_from < '2012-01-31 13:39:26' AND battles.valid_to > '2012-01-31 13:39:26') ORDER BY battles.id DESC
BattleCategory Load (0.1ms) SELECT `battle_categories`.* FROM `battle_categories` WHERE `battle_categories`.`id` IN (1)
Bet Load (0.1ms) SELECT `bets`.* FROM `bets` WHERE `bets`.`parent_type` = 'Battle' AND `bets`.`parent_id` IN (1,2)
Vote Load (0.2ms) SELECT `votes`.* FROM `votes` WHERE `votes`.`parent_type` = 'Battle' AND `votes`.`parent_id` IN (1,2)
BattleVideo Load (0.3ms) SELECT `battle_videos`.* FROM `battle_videos` WHERE `battle_videos`.`battle_id` IN (1,2) AND (battle_videos.code = 'left_side')
Video Load (0.1ms) SELECT `videos`.* FROM `videos` WHERE `videos`.`id` IN (1, 3)
Video Load (0.2ms) SELECT `videos`.* FROM `videos` INNER JOIN `battle_videos` ON `videos`.`id` = `battle_videos`.`video_id` WHERE `battle_videos`.`battle_id` = 1 AND (battle_videos.code = 'right_side') LIMIT 1
Video Load (0.1ms) SELECT `videos`.* FROM `videos` INNER JOIN `battle_videos` ON `videos`.`id` = `battle_videos`.`video_id` WHERE `battle_videos`.`battle_id` = 2 AND (battle_videos.code = 'right_side') LIMIT 1
现在这工作正常。但在 SQL 级别 - 它并不像我想要的那样完美。您可以看到,视频 1、3 以正确的方式加载
Video Load (0.1ms) SELECT `videos`.* FROM `videos` WHERE `videos`.`id` IN (1, 3)
但视频 2、4 由单独的 sql 加载:
Video Load (0.2ms) SELECT `videos`.* FROM `videos` INNER JOIN `battle_videos` ON `videos`.`id` = `battle_videos`.`video_id` WHERE `battle_videos`.`battle_id` = 1 AND (battle_videos.code = 'right_side') LIMIT 1
Video Load (0.1ms) SELECT `videos`.* FROM `videos` INNER JOIN `battle_videos` ON `videos`.`id` = `battle_videos`.`video_id` WHERE `battle_videos`.`battle_id` = 2 AND (battle_videos.code = 'right_side') LIMIT 1
我想要什么? 由 RUBY 生成的最终 SQL
Video Load (0.1ms) SELECT `videos`.* FROM `videos` WHERE `videos`.`id` IN (1, 2, 3, 4)
【问题讨论】:
-
所以你想在一个请求中获取 Rails 加载的所有视频,使用什么代码?这个:
battle.videos.left_side不可接受? -
是的。你很紧张,1 个请求 - 所有视频
-
left_side|right_side
code存储在 assoc 模型BattleVideo中而不是模型Video -
所以最后你只想得到 1 个
Video的请求并且还有 3 个不同的关联? IE。没有更多的查询?看起来你应该从现有的缓存集合中按类型在 ruby 中进行所有过滤。
标签: ruby-on-rails ruby ruby-on-rails-3 associations has-many-through