Ruby on rails ActiveRecord作用域唯一性验证与MySQL复合唯一索引

Ruby on rails ActiveRecord作用域唯一性验证与MySQL复合唯一索引,ruby-on-rails,validation,activerecord,Ruby On Rails,Validation,Activerecord,首先,让我来准备一下: 我有一个app\u settings表,它将app\u setting\u选项与user\u id、user\u role\u id、event\u id、group\u id或app\u level\u setting。对于任何给定的app\u设置,都应该有一个特定的app\u设置选项\u id,并且只有一个其他对象。对于这些次要对象中的每一个,我都在AppSetting模型中指定了一个作用域的唯一性验证: validates :user_id, uniqueness:

首先,让我来准备一下:

我有一个
app\u settings
表,它将
app\u setting\u选项
user\u id
user\u role\u id
event\u id
group\u id
app\u level\u setting
。对于任何给定的
app\u设置
,都应该有一个特定的
app\u设置选项\u 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\u设置
选项和一个特定的
user\u id
创建一个
app\u设置
,然后再次尝试做同样的事情。验证阻止了这种情况的发生。它与
用户角色
事件
、以及
完美配合。问题在于
app\u level\u设置
以某种方式使其通过了验证,并被数据库级别的复合唯一索引阻止,从而得到一个
Mysql2::Error:Duplicate条目

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_设置不是因为数据库上的索引而创建的,也不是因为验证。布尔值上的唯一性验证是否有特定的内容?当我尝试在控制台中创建相同的
app\u level\u设置时,也会出现相同的错误。

对于布尔字段验证,不能设置唯一性验证。 要验证布尔字段,可以执行以下操作:

validates :field, :inclusion => {:in => [true, false]}

最后,我必须创建一个自定义验证,如下所示:

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
然后我的测试如下:

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

是否有可能确定范围?我想确保对于任何特定的
app\u设置\u选项\u id
,只有一条记录的app\u level\u设置==true。这有意义吗?您可以使用app\u setting\u option\u id.Ok来确定范围,但其语法是什么?范围在哪里?