簡體   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