Der*_*mer 3 ruby ruby-on-rails foreign-keys
我花了一些时间来追查这个错误,但我终于找到了原因.我正在使用Rails框架为纸牌游戏建模.目前我的数据库(大多数)看起来像这样:
cards cards_games games
----- ----------- -----
id id id
c_type card_id ...
value game_id other_stuff
Run Code Online (Sandbox Code Playgroud)
Rails ActiveRecord card.rb和game.rb目前看起来像这样
#card.rb
class Card < ActiveRecord::Base
has_and_belongs_to_many :player
has_and_belongs_to_many :game
has_and_belongs_to_many :cardsInPlay, :class_name => "Rule"
end
Run Code Online (Sandbox Code Playgroud)
#game.rb
class Game < ActiveRecord::Base
has_and_belongs_to_many :cards
has_many :players
has_one :rules, :class_name => Rule
end
Run Code Online (Sandbox Code Playgroud)
当我尝试运行游戏并且有多个游戏(超过1个)时,我收到错误
ActiveRecord::StatementInvalid in GameController#start_game
# example
Mysql::Error: Duplicate entry '31' for key 1: INSERT INTO `cards_games` (`card_id`, `id`, `game_id`) VALUES (31, 31, 7)
Run Code Online (Sandbox Code Playgroud)
每次动作失败时,cardid == id.我认为,这与Rails如何将数据插入数据库有关.由于没有cardgames对象,我认为它只是将card_id拉入id并将其插入数据库.这可以正常工作,直到你有两张同一张牌的游戏,这违反了卡片游戏的主键约束.由于数据库比较丰富,我对此问题的第一个解决方案是尝试强制rails通过删除id并将cardid和gameid作为主键来遵循这种关系的"真实"定义.它没有用,因为迁移似乎无法处理两个主键(尽管Rails API说它可以做到这一点......很奇怪).另一个解决方案是省略INSERT INTO语句中的'id'列,让数据库处理自动增量.不幸的是,我也不知道该怎么做.
那么,还有另一种解决办法吗?是否有一些我不知道的漂亮的Rails技巧?或者这种结构在Rails中是不可能的?这真是令人沮丧,因为我知道什么是错的,我知道有几种方法可以修复它但是由于Rail框架的限制,我无法做到.
Ste*_*sen 10
has_and_belongs_to_many表示连接表,它不能有id主键列.将迁移更改为
create_table :cards_games, :id => false do ...
Run Code Online (Sandbox Code Playgroud)
正如马特指出的那样.如果从两列中创建一个键,只会睡得更好,请在它们上创建一个唯一索引:
add_index :cards_games, [ :card_id, :game_id ], :unique => true
Run Code Online (Sandbox Code Playgroud)
此外,您的命名与Rails惯例不同,将使您的代码更难阅读.
has_and_belongs_to_many在查看类的实例时定义1:M关系.所以Card,你应该使用:
has_and_belongs_to_many :players
has_and_belongs_to_many :games
Run Code Online (Sandbox Code Playgroud)
注意复数"玩家"和"游戏".同样在Game:
has_one :rule
Run Code Online (Sandbox Code Playgroud)
这也可以让你放弃不必要的东西:class_name => Rule.
| 归档时间: |
|
| 查看次数: |
4849 次 |
| 最近记录: |