Rails,使用 belongs_to 和 has_one 关联到相同的 class
Rails, using a belongs_to and has_one association to the same class
这是我制作的图片,直观地描述了我正在寻找的关系:
在图片中我说 Interaction
,但更具体地说,这些互动是 in-game 击杀。杀戮,众所周知,有凶手,也有受害者。在这种情况下,我们的凶手将被称为 player
,而我们的受害者将被称为 victim
.
鉴于此图片,这里是我想要执行的一些示例查询:
Player.find(1).Interactions
> [<#Interaction id: 1>, <#Interaction id: 2>, <#Interaction id: 3>]
Interactions.where(player: Player.find(1))
> [<#Interaction id: 1>, <#Interaction id: 2>, <#Interaction id: 3>]
Interactions.where(victim: Player.find(1))
> [<#Interaction id: 4>]
Player.find(1).Interactions.where(victim: Player.find(2))
> [<#Interaction id: 2>]
Player.find(1).Interactions.count()
> 3
# Player.find(1).Interactions should (ideally) return Interactions where <#Player id: 1> is the player (not victim)
Interactions.all.count()
> 4
Player.all.count()
> 4
Player.find(2).Interactions
> []
Player.find(3).Interactions
> [ <#Interaction id: 4> ]
Player.find(4).Interactions
> []
我尝试了很多不同的关联(我已经研究了 google 和 Stack Overflow 结果数小时)
我认为我的 Interaction
模型应该是这样的:
class Interaction < ActiveRecord::Base
belongs_to :player
has_one :victim, :class_name => 'Player'
end
还有我的 Player
模特:
class Player < ActiveRecord::Base
has_man :kills
end
最后,我认为迁移应该是什么样子:
class CreatePlayerAndInteraction < ActiveRecord::Migration[5.0]
def change
create_table :players do |t|
t.string :steam_id
end
create_table :interactions do |t|
t.string :weapon
t.belongs_to :player, index: true
end
end
interactions
table 只需要一个 victim_id
列,然后将 has_one
更改为 belongs_to :victim, class_name: Player
。
这将起作用,因为 Interaction
基本上是 Player
到 Player
的连接 table。
has_one
暗示受害者(在本例中为 Player
)会有一个 interaction_id
,这是不正确的。
相反,Interaction
属于凶手和受害者。
设置为:
class Player
has_many :kills, class_name: Interaction, foreign_key: :player_id inverse_of: :killer
has_many :deaths, class_name: Interaction, foreign_key: :victim_id, inverse_of: :victim
end
class Interaction
belongs_to :killer, class_name: Player, foreign_key: :player_id, inverse_of: :kills
belongs_to :victim, class_name: Player, foreign_key: :victim_id, inverse_of :deaths
end
engineersmnky 给了我一个很好的答案,帮助我解决了这个问题,但它有更多的绒毛。这是我用来解决问题的确切解决方案:
# ./models/player.rb
class Player < ActiveRecord::Base
has_many :interactions
end
# ./models/interaction.rb
class Interaction < ActiveRecord::Base
belongs_to :player
belongs_to :victim, class_name: 'Player', foreign_key: 'victim_id'
end
# ./db/migrate/migrate/create_players.rb
class CreatePlayersAndInteractions < ActiveRecord::Migration[5.0]
def change
create_table :interactions do |t|
t.integer :victim_id
t.belongs_to :player, index: true
end
end
end
这是我制作的图片,直观地描述了我正在寻找的关系:
在图片中我说 Interaction
,但更具体地说,这些互动是 in-game 击杀。杀戮,众所周知,有凶手,也有受害者。在这种情况下,我们的凶手将被称为 player
,而我们的受害者将被称为 victim
.
鉴于此图片,这里是我想要执行的一些示例查询:
Player.find(1).Interactions
> [<#Interaction id: 1>, <#Interaction id: 2>, <#Interaction id: 3>]
Interactions.where(player: Player.find(1))
> [<#Interaction id: 1>, <#Interaction id: 2>, <#Interaction id: 3>]
Interactions.where(victim: Player.find(1))
> [<#Interaction id: 4>]
Player.find(1).Interactions.where(victim: Player.find(2))
> [<#Interaction id: 2>]
Player.find(1).Interactions.count()
> 3
# Player.find(1).Interactions should (ideally) return Interactions where <#Player id: 1> is the player (not victim)
Interactions.all.count()
> 4
Player.all.count()
> 4
Player.find(2).Interactions
> []
Player.find(3).Interactions
> [ <#Interaction id: 4> ]
Player.find(4).Interactions
> []
我尝试了很多不同的关联(我已经研究了 google 和 Stack Overflow 结果数小时)
我认为我的 Interaction
模型应该是这样的:
class Interaction < ActiveRecord::Base
belongs_to :player
has_one :victim, :class_name => 'Player'
end
还有我的 Player
模特:
class Player < ActiveRecord::Base
has_man :kills
end
最后,我认为迁移应该是什么样子:
class CreatePlayerAndInteraction < ActiveRecord::Migration[5.0]
def change
create_table :players do |t|
t.string :steam_id
end
create_table :interactions do |t|
t.string :weapon
t.belongs_to :player, index: true
end
end
interactions
table 只需要一个 victim_id
列,然后将 has_one
更改为 belongs_to :victim, class_name: Player
。
这将起作用,因为 Interaction
基本上是 Player
到 Player
的连接 table。
has_one
暗示受害者(在本例中为 Player
)会有一个 interaction_id
,这是不正确的。
相反,Interaction
属于凶手和受害者。
设置为:
class Player
has_many :kills, class_name: Interaction, foreign_key: :player_id inverse_of: :killer
has_many :deaths, class_name: Interaction, foreign_key: :victim_id, inverse_of: :victim
end
class Interaction
belongs_to :killer, class_name: Player, foreign_key: :player_id, inverse_of: :kills
belongs_to :victim, class_name: Player, foreign_key: :victim_id, inverse_of :deaths
end
engineersmnky 给了我一个很好的答案,帮助我解决了这个问题,但它有更多的绒毛。这是我用来解决问题的确切解决方案:
# ./models/player.rb
class Player < ActiveRecord::Base
has_many :interactions
end
# ./models/interaction.rb
class Interaction < ActiveRecord::Base
belongs_to :player
belongs_to :victim, class_name: 'Player', foreign_key: 'victim_id'
end
# ./db/migrate/migrate/create_players.rb
class CreatePlayersAndInteractions < ActiveRecord::Migration[5.0]
def change
create_table :interactions do |t|
t.integer :victim_id
t.belongs_to :player, index: true
end
end
end