HABTM-- 唯一性约束

发布于 2024-10-17 01:15:54 字数 361 浏览 4 评论 0原文

我有两个具有 HABTM 关系的模型 - 用户和角色。

  • user - has_and_belongs_to_many :roles
  • role - own_to :user

我想在联接(users_roles 表)中添加唯一性约束,表示 user_id 和 role_id 必须是唯一的。在 Rails 中,看起来像:

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

当然,在 Rails 中,我们通常没有模型来表示 HABTM 关联中的连接关系。

所以我的问题是添加约束的最佳位置在哪里?

I have two models with a HABTM relationship - User and Role.

  • user - has_and_belongs_to_many :roles
  • role - belongs_to :user

I want to add a uniqueness constraint in the join (users_roles table) that says the user_id and role_id must be unique. In Rails, would look like:

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

Of course, in Rails, we don't usually have a model to represent the join relationship in a HABTM association.

So my question is where is the best place to add the constraint?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

简单 2024-10-24 01:15:54

您可以为联接表添加唯一性

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

,请参阅在连接表中,Rails 缺少组合键的最佳解决方法是什么?

那么您的数据库将引发异常,您必须处理该异常。
我不知道任何准备好在这种情况下使用 Rails 验证,但您可以添加自己的验证,如下所示:

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::Rollback 在内部捕获但不会重新引发。

编辑

不要使用我添加自定义验证的部分。它有点有效,但还有更好的选择。

按照 @Spyros 在另一个答案中建议的方式使用 :uniq 关联选项:(

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

此代码片段来自 Rails Guides v.3)。阅读 Rails Guides v 3.2.13 的外观for 4.4.2.19 :uniq

Rails Guide v.4 特别警告不要使用 include? 检查唯一性,因为可能存在竞争条件。

关于为连接表添加索引的部分保留。

You can add uniqueness to join table

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

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

Your database will raise an exception then, which you have to handle.
I don't know any ready to use rails validation for this case, but you can add your own validation like this:

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

I would just silently drop the database call and report success.

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

ActiveRecord::Rollback is internally captured but not reraised.

Edit

Don't use the part where I'm adding custom validation. It kinda works but there is better alternatives.

Use :uniq option on association as @Spyros suggested in another answer:

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

(this code snippet is from Rails Guides v.3). Read up on Rails Guides v 3.2.13 look for 4.4.2.19 :uniq

Rails Guide v.4 specifically warns against using include? for checking for uniqueness because of possible race conditions.

The part about adding an index to join table stays.

瘫痪情歌 2024-10-24 01:15:54

在 Rails 5 中,您需要使用 distinct 而不是 uniq

另外,尝试这样做以确保唯一性

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

In Rails 5 you'll want to use distinct instead of uniq

Also, try this for ensuring uniqueness

has_and_belongs_to_many :foos, -> { distinct } do
  def << (value)
    super value rescue ActiveRecord::RecordNotUnique
  end
end
夜还是长夜 2024-10-24 01:15:54

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

(当然名称和描述是您的列值)

I think that using :uniq => true would ensure that you get no duplicate objects. But, if you want to check on whether a duplicate exists before writing a second one to your db, i would probably use find_or_create_by_name_and_description(...).

(Of course name and description are your column values)

街道布景 2024-10-24 01:15:54

我更喜欢

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

其他选项参考此处

I prefer

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

other options reference here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文