我有两个型号Game
& Theme
他们有一个has_and_belongs_to_many关联。我已经尝试了许多解决方案来防止games_themes
表中的重复记录,但没有解决方案可行。问题是,games_themes
是一个表,但它不是一个模型,所以我无法找到一种方法来有效地运行验证。
这是我试过的解决方案
class Theme < ActiveRecord::Base
has_and_belongs_to_many :games, :uniq => true
end
class Game < ActiveRecord::Base
has_and_belongs_to_many :themes, :uniq => true
end
答案 0 :(得分:14)
您应该使用数据库级验证:
#new_migration
add_index :games_themes, [:game_id, :theme_id], :unique => true
<强> HABTM 强>
这将阻止您保存数据库中的任何重复数据。减轻Rails&amp;确保您只有游戏或主题。问题是因为HABTM没有模型,没有你可以在Rails中执行的验证,这意味着你需要使它成为db-level
正如评论中所提到的,这意味着你必须像这样处理从db中引发的异常:
#app/controllers/games_controller.rb
def create
#creation stuff here
if @game.save
#successful save
else
#capture errors
end
end
答案 1 :(得分:4)
使用:
validates_uniqueness_of :theme_id, :scope => :game_id
如下:
class Theme < ActiveRecord::Base
has_many :games, through: :games_themes
end
class Game < ActiveRecord::Base
has_many :themes, through: :games_themes
end
class GamesThemes < ActiveRecord::Base
belongs_to :game
belongs_to :theme
validates_uniqueness_of :theme_id, :scope => :game_id
end
答案 2 :(得分:1)
要在联接表上运行验证,您应该使用has_many :through
关联。
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
答案 3 :(得分:0)
创建新模型GameTheme用于验证目的不是一个好主意。我们可以在迁移中验证自己。
主题模型:
class Theme < ActiveRecord::Base
has_and_belongs_to_many :games,
:association_foreign_key => 'theme_id',
:class_name => 'Theme',
:join_table => 'games_themes'
end
游戏模型:
class Theme < ActiveRecord::Base
has_and_belongs_to_many :games,
:association_foreign_key => 'game_id',
:class_name => 'Game',
:join_table => 'games_themes'
end
games_themes迁移: 您可以为连接表添加唯一性,有关详细信息,请查看here。
class GamesThemesTable < ActiveRecord::Migration
def self.up
create_table :games_themes, :id => false do |t|
t.references :game
t.references :theme
end
add_index :games_themes, [:theme_id, :game_id], :unique => true
end
def self.down
drop_table :games_themes
end
end