2011-02-14 128 views
16

我有两个模型与HABTM关系 - 用户和角色。HABTM - 唯一性约束

  • 用户 - has_and_belongs_to_many:角色
  • 角色 - belongs_to的:用户

我想在连接(users_roles表)唯一性约束添加写着USER_ID和ROLE_ID必须是唯一的。在Rails中,看起来像:

validates_uniqueness_of :user, :scope => [:role] 

当然,在Rails中,我们通常不会有一个模型来表示在HABTM关联的联接关系。

所以我的问题是哪里是最好的地方添加约束?

回答

36

您可以添加独特的加盟表

add_index :users_roles, [ :user_id, :role_id ], :unique => true, :name => 'by_user_and_role' 

看到In a join table, what's the best workaround for Rails' absence of a composite key?

您的数据库将引发异常的话,你有处理。
我不知道任何准备使用轨验证了这种情况,但您可以添加自己的验证这样的:

class User < ActiveRecord::Base 
has_and_belongs_to_many :roles, :before_add => :validates_role 

我只想默默地删除数据库调用,并报告成功。

def validates_role(role) 
    raise ActiveRecord::Rollback if self.roles.include? role 
end 

ActiveRecord ::回滚是在内部捕获但不能重新加入。

编辑

请勿在我添加自定义的验证的一部分。它有点有用,但有更好的选择。在协会评为@Spyros

使用:uniq选项的另一种回答提示:

class Parts < ActiveRecord::Base 
    has_and_belongs_to_many :assemblies, :uniq => true, :read_only => true 
end 

(此代码段是从Rails的指南第3节)。请阅读Rails Guides v 3.2.13寻找4.4.2.19:uniq

Rails指南第4版特别警告不要使用include?来检查由于可能的竞争条件造成的唯一性。

有关添加索引来连接表的部分保留。

+0

感谢您的支持!我最终将其用于用户和组的HABTM实例(本质上是相同类型的角色设置)。 – dennismonsewicz 2012-05-09 03:31:53

+1

与`:has_many`不同,它会吸引一点,重复数据删除不会自动处理habtm关联。编辑后张贴 – prusswan 2013-07-04 04:09:51

+1

。 我发布了这个答案,并忘记了它。然后我遇到了一个相关的问题,我记得我有一个答案人保持upvoting,我检查了它和OMG!我在想什么! 我希望没有人有任何问题,因为他用我的答案。没有那个我感觉很糟糕。 那对我们所有人来说都是一个教训。你在Stackoverflow上匆忙地留下了一个马虎的回答,并忘记了它,但时间到了,它会涌向你,并咬你屁股。 – 2013-09-21 09:12:50

5

我认为使用:uniq => true将确保您没有重复的对象。但是,如果你想在写入第二个到你的数据库之前检查是否存在重复,我可能会使用find_or_create_by_name_and_description(...)。

(当然名字和描述你的列值)

5

我喜欢

class User < ActiveRecord::Base 
    has_and_belongs_to_many :roles, -> { uniq } 
end 

其他选项参考here

4

在Rails 5,你会想用distinct代替uniq

此外,尝试一下本作保证唯一性

has_and_belongs_to_many :foos, -> { distinct } do 
    def << (value) 
    super value rescue ActiveRecord::RecordNotUnique 
    end 
end