首先,让我设定阶段:
我有一个app_settings
表,可以app_setting_options
与user_id
,user_role_id
,event_id
,group_id
或app_level_setting
相关联。对于任何给定的app_setting
,应该有一个特定的app_setting_option_id
且只有一个的其他对象。对于每个辅助对象,我已在AppSetting
模型中使用范围指定了唯一性验证:
validates :user_id, uniqueness: { scope: :app_setting_option_id}, allow_nil: true
validates :user_role_id, uniqueness: { scope: :app_setting_option_id}, allow_nil: true
validates :group_id, uniqueness: { scope: :app_setting_option_id}, allow_nil: true
validates :event_id, uniqueness: { scope: :app_setting_option_id}, allow_nil: true
validates :app_level_setting, uniqueness: { scope: :app_setting_option_id}, allow_nil: true
最重要的是,我还在数据库中的每个辅助对象上都有一个复合唯一索引。通常我会依赖ActiveRecord验证来处理任何奇怪的边缘情况,但是(长话短说)往往会有相当数量的直接数据库调整发生,我们想要阻止一些无意的事情发生。
在我的测试中,我创建了一个app_setting
,其中包含特定的app_setting_option
和一个特定的user_id
,然后尝试再次执行完全相同的操作。验证可以阻止这种情况发生。它与user_role
,event
和group
完美配合。问题在于app_level_setting
,它以某种方式使其超过验证并被数据库级别的复合唯一索引停止,获得Mysql2::Error: Duplicate entry
。
it 'app_level_setting uniqueness' do
app_setting_option = AppSettingOption.find(21)
create(:app_setting, app_setting_option: app_setting_option, app_level_setting: 1)
create(:app_setting, app_setting_option: app_setting_option, app_level_setting: 1)
end
由于数据库上的索引而未创建第二个app_setting,而不是因为验证。是否有关于布尔值的唯一性验证的具体内容?当我尝试在控制台中创建相同的app_level_setting
时,我得到了同样的错误。
答案 0 :(得分:0)
对于布尔字段验证,您无法设置唯一性验证。 为了验证布尔字段,您可以执行类似的操作,
validates :field, :inclusion => {:in => [true, false]}
答案 1 :(得分:0)
最后,我必须按如下方式创建自定义验证:
validate :app_level_setting_validation
def app_level_setting_validation
errors.add(:app_setting, "app level setting already exists") if app_setting_option.app_setting_type_id == 1 && AppSetting.find_by(app_setting_option_id: app_setting_option.id, app_level_setting: true).present?
end
然后我的测试如下:
it 'App level setting uniqueness' do
app_setting_option = create(:app_setting_option)
create(:app_setting, app_setting_option: app_setting_option, app_level_setting: true)
setting = build(:app_setting, app_setting_option: app_setting_option, app_level_setting: true)
setting.should_not be_valid
end