繁体   English   中英

通过关联设置has_many

[英]Setting up has_many through association

我有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具有属性“代码”(left_side || right_side),该属性确定了战斗面(战斗中总是有2面,战斗总是持续-1对1,团队对团队等)

我想在模型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)

为什么不尝试使用“联接”而不是“包含”?

您可以像这样创建named_scope

    named_scope : left_side_video, {
      :select => "videos.*",
      :joins => "INNER JOIN battle_videos ON battle_videos.video_id = videos.id INNER JOIN battles on battles.id = battle_videos.battle_id", 
      :conditions=>"battle_videos.code = 'left_side'"
    }

尚未测试。 但是完美的查询应该或多或少是相似的。

我认为,应该使用preload而不是includes来加载关联。

范围:all_inclusive,preload(:battle_category,:bets,:votes,:left_side_video,:right_side_video)

preload不会影响原始查询,它会为您指定的每个关联进行单独的查询。

它在rails 3.0.x中很好用。 Dunno您使用的是哪个版本,可能会有所不同...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM