HABTM重复记录

时间:2014-02-20 01:49:44

标签: ruby-on-rails ruby ruby-on-rails-3 associations

我有两个型号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

4 个答案:

答案 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