Ruby on rails Rails:忽略某些记录验证唯一性
我们正在使用RubyonRails4 我的“事件”模型有:Ruby on rails Rails:忽略某些记录验证唯一性,ruby-on-rails,Ruby On Rails,我们正在使用RubyonRails4 我的“事件”模型有: “标题”字段,可以是任意字符串 作为约定表索引的约定id字段 一个状态字段,可以是“提议”、“讨论”、“接受”、“拒绝”或“放弃” 我想创建一个validates语句,以确保标题在约定中是唯一的。这是最简单的部分 validates :title, :uniqueness => { :scope => :convention_id } 做我想做的事。但我想忽略任何状态为“已拒绝”或“已删除”的记录。我真正想要的是向SQ
- “标题”字段,可以是任意字符串
- 作为约定表索引的约定id字段
- 一个状态字段,可以是“提议”、“讨论”、“接受”、“拒绝”或“放弃”
validates :title, :uniqueness => { :scope => :convention_id }
做我想做的事。但我想忽略任何状态为“已拒绝”或“已删除”的记录。我真正想要的是向SQLRails生成的语句中添加一些WHERE子句,但我不确定如何添加
感谢您的帮助。,您可以通过带有排除条件的:
validates :title,
uniqueness: {scope: :convention_id},
unless: Proc.new { |event| event.status == "Rejected" || event.status == "Dropped" }
请注意,哈希火箭(=>
)的使用必须一致。在上面的示例中,我用JSON样式的符号替换了hash rocket语法(事实上是Rails 4的符号),但是可以重写整个语句以使用hash rocket,如下所示:
validates :title,
:uniqueness => {:scope => :convention_id},
:unless => Proc.new { |event| event.status == "Rejected" || event.status == "Dropped" }
我找到了答案。以下内容似乎与我预期的一样有效:
validates_uniqueness_of :title,
scope: :convention,
conditions: -> { where.not(status: ['Dropped', 'Rejected']) }
生成的SQL是
SELECT 1 AS one FROM "events"
WHERE ("events"."title" = 'Panel' AND
"events"."id" != 2 AND
"events"."convention_id" = 1) AND
("events"."status" NOT IN ('Dropped', 'Rejected'))
LIMIT 1
我想这正是我想要的
再次感谢您的帮助。使用
验证创建验证的另一种方法可能是
到目前为止,这方面有什么进展吗?我认为您需要编写自定义验证来实现这一点,除非您引入另一个专栏,否则我们称之为活动。如果前三个状态为活动状态,后两个状态为非活动状态,则可以使用作用域:scope=>[:convention\u id,:active]
,当然,然后active
会复制status
列中的信息,这通常是个坏主意。我将开始探索如何编写自定义验证。谢谢。请澄清一下,当您说要忽略已拒绝或已删除的记录时,您的意思是什么?状态设置为“已拒绝”或“已删除”的记录可以有重复的标题。但这不起作用。它失败了,错误为{:title=>[“已被接受”]},development.log没有显示SQL上的WHERE子句。我认为这与OP想要的相反。OP询问,如果标题在约定范围内是唯一的,则对象是否有有效的方法,除了拒绝的
或放弃的
之外。您编写的内容将允许添加被拒绝/删除的记录。按照我对问题的解释,OP希望验证未被拒绝或删除的记录,这就是它应该做的。坦率地说,这个问题措辞不好。@user2062850,为什么需要WHERE
子句?我已经检查了此查询,它确实应该达到您在问题和后续评论中指定的预期结果。WHERE
子句用于跳过对状态为“拒绝”或“已删除”的事件的检查。我创建了一个事件,将其状态设置为“已删除”并保存。然后,我创建了第二个标题相同的事件,并试图保存它。上面的代码拒绝了第二次保存,因为它与第一个事件的标题相匹配,尽管状态设置为“已删除”。下面使用conditions
子句的解决方案在SQL中添加了一个WHERE
子句,以跳过查看任何状态为“drop”或“Rejected”的行,因此第二次保存成功。我提供的答案生成了一个更简洁的SQL查询。您能否说明此答案如何更有效地满足您的问题?使用除非子句的解决方案是检查正在验证的事件,而不是与数据库中已有的事件进行比较。因此,当我创建一个事件并将其状态设置为dropped,然后创建第二个事件时,第二次保存失败,因为它正在查找匹配项。使用conditions子句,第二次保存成功,因为第一个事件的状态为“Dropped”,并且与查询不匹配。
validates :title,
uniqueness: { scope: :convention, conditions: -> { where.not(status: ['Dropped', 'Rejected']) }