我有一个Ticket
模型,对字符串属性ticket_number
进行基本唯一性验证
validates :ticket_number, uniqueness: true
以下是ticket_number
<%= f.number_field :ticket_number, :value => @ticket.ticket_number || (Ticket.exists? ? Ticket.maximum(:ticket_number).next) : 1 , :class => 'form-control' %>
验证似乎按预期工作,但是当我们部署应用程序时,可能有多个用户同时输入tickets
,这不应该导致问题(对吗?)我们发现了重复的记录(数据库中的相同票号)(MySQL)。
到目前为止,总共600多张门票中只发生过一次,但为什么以及如何防止这种情况发生呢?
答案 0 :(得分:2)
这是非常罕见的,你可能非常不走运,这是可能的。
请考虑以下事项: 用户A提交表单
这一切都必须在几毫秒内完成,但技术上可行。
我建议在数据库级别添加约束(主键)。
答案 1 :(得分:1)
@Yule的答案非常有用,它解释了为什么会发生这种情况,并且添加数据库级别约束会阻止它。
docs说,这会抛出ActiveRecord::RecordNotUnique
exseption,我不希望用户看到当然,所以这里是如何应用@Yule建议的解决方法:
在属性上添加索引
add_index(:tickets, :ticket_number, :unique => true)
调整controller#create
操作以捕获数据库异常:
def create
@ticket = Ticket.new(ticket_params)
if @ticket.save
flash[:success] = 'Ticket was successfully created.'
else
render action: 'new'
end
#catch the exception
rescue ActiveRecord::RecordNotUnique
flash[:danger] = 'The ticket number you entered is already taken !'
render action: 'new'
end
应该对控制器#review action ofcourse
做同样的事情