简体   繁体   English

通过关联设置has_many

[英]Setting up has_many through association

I have 3 models 我有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 has attribute "code" (left_side || right_side) which determines BATTLE SIDE (there are always 2 sides in battles, coz always playing -- 1 vs. 1, team vs. team etc.) BattleVideo具有属性“代码”(left_side || right_side),该属性确定了战斗面(战斗中总是有2面,战斗总是持续-1对1,团队对团队等)

I would like to specify association (left_side_video, right_side_video) in model video , which gets video for chosen side. 我想在模型video中指定关联(left_side_video,right_side_video),该关联会获取所选边的视频。

Now to get video for SIDE 1 (left) - use this code 现在获取SIDE 1(左侧)的视频-使用此代码

Battle.first.battle_videos.where("battle_videos.code = 'left_side'").first.video

I want to get my battle videos like this 我想得到这样的战斗视频

Battle.first.left_side_video

I think, Battle model should look like this, but it doesnt work (works only left side) 我认为,战斗模型应如下所示,但它不起作用(仅在左侧起作用)

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

UPDATE: Works, but not in desired way. 更新:有效 ,但不按预期方式。 The problem was in includes chain. 问题出在includes连锁。 model Battle has scope :all_inclusive , which loads all associations Battle模型具有范围:all_inclusive ,它会加载所有关联

scope :all_inclusive, includes(:battle_category).includes(:bets).includes(:votes).includes(:left_side_video).includes(:right_side_video)

Generated SQL: 生成的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)

NOTICE THAT VIDEOS 2 AND 4 (FOR RIGHT SIDE) - dont load. 注意视频2和4(在右侧)-不要加载。 I can access only 1,3 videos 我只能访问1,3个视频

Videos id, battle_id (side) 影片ID,Battle_id(侧面)

[1 , 1 (lft)] [1,1(lft)]

[2 , 1 (rgt)] [2,1(rgt)]

[3 , 2 (lft)] [3,2(lft)]

[4 , 2 (rgt)] [4,2(rgt)]

When I remove .includes(:right_side_video) from :all_inclusive chain I got this sql: 当我从: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

Now this works fine. 现在可以正常工作了。 But IN SQL level - its not as perfect as I want. 但是在SQL级别上-并不是我想要的那么完美。 You can see, that videos 1, 3 are loaded in correct way 您可以看到视频1、3的加载方式正确

Video Load (0.1ms)  SELECT `videos`.* FROM `videos` WHERE `videos`.`id` IN (1, 3)

But video 2, 4 load by seperate sqls: 但是视频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

What I want? 我想要的是? FINAL SQL GENERATED BY RUBY RUBY生成的最终SQL

Video Load (0.1ms)  SELECT `videos`.* FROM `videos` WHERE `videos`.`id` IN (1, 2, 3, 4)

Why don't you try with "joins" instead of "includes"? 为什么不尝试使用“联接”而不是“包含”?

You can create named_scope like this 您可以像这样创建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'"
    }

Haven't tested this yet. 尚未测试。 But the perfect query should be more or less the similar one. 但是完美的查询应该或多或少是相似的。

I think, you should use preload instead of includes for loading associations. 我认为,应该使用preload而不是includes来加载关联。

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

preload doesn't affect original query, it makes separate query for every association you specify. preload不会影响原始查询,它会为您指定的每个关联进行单独的查询。

It works great in rails 3.0.x. 它在rails 3.0.x中很好用。 Dunno which version you use, it may differ... Dunno您使用的是哪个版本,可能会有所不同...

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

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