ker*_*lin 17 ruby-on-rails unique-constraint has-and-belongs-to-many
我有两个具有HABTM关系的模型 - 用户和角色.
我想在join(users_roles表)中添加一个唯一性约束,表示user_id和role_id必须是唯一的.在Rails中,看起来像:
validates_uniqueness_of :user, :scope => [:role]
Run Code Online (Sandbox Code Playgroud)
当然,在Rails中,我们通常没有一个模型来表示HABTM关联中的连接关系.
所以我的问题是添加约束的最佳位置在哪里?
Art*_*rov 37
您可以为连接表添加唯一性
add_index :users_roles, [ :user_id, :role_id ], :unique => true, :name => 'by_user_and_role'
Run Code Online (Sandbox Code Playgroud)
请参阅在连接表中,Rails缺少复合键的最佳解决方法是什么?
您的数据库将引发异常,您必须处理该异常.
我不知道在这种情况下是否准备好使用rails验证,但您可以像这样添加自己的验证:
class User < ActiveRecord::Base
has_and_belongs_to_many :roles, :before_add => :validates_role
Run Code Online (Sandbox Code Playgroud)
我会默默地删除数据库调用并报告成功.
def validates_role(role)
raise ActiveRecord::Rollback if self.roles.include? role
end
Run Code Online (Sandbox Code Playgroud)
ActiveRecord :: Rollback是内部捕获但未重新加载.
编辑
不要使用我正在添加自定义验证的部分.它有点工作,但有更好的选择.
使用:uniq@Spyros在另一个答案中建议的关联选项:
class Parts < ActiveRecord::Base
has_and_belongs_to_many :assemblies, :uniq => true, :read_only => true
end
Run Code Online (Sandbox Code Playgroud)
(此代码段来自Rails Guides v.3).阅读Rails指南v 3.2.13,了解4.4.2.19:uniq
Rails指南v.4特别警告不要include?因为可能的竞争条件而使用检查唯一性.
关于为连接表添加索引的部分保留.
我认为使用:uniq => true会确保您没有重复的对象.但是,如果要在将第二个副本写入数据库之前检查是否存在重复,我可能会使用find_or_create_by_name_and_description(...).
(当然,名称和描述是您的列值)
我更喜欢
class User < ActiveRecord::Base
has_and_belongs_to_many :roles, -> { uniq }
end
Run Code Online (Sandbox Code Playgroud)
其他选项在这里参考
在Rails 5中,您将要使用distinct而不是uniq
另外,请尝试这样做以确保唯一性
has_and_belongs_to_many :foos, -> { distinct } do
def << (value)
super value rescue ActiveRecord::RecordNotUnique
end
end
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7865 次 |
| 最近记录: |