我的rails应用程序有一个奇怪的问题。我的应用程序在一秒钟内接受重复的POST请求
此重复请求包含相同的数据,奇怪地能够绕过我的模型的唯一性验证。这导致创建具有完全相同内容的两行数据。
让我感到困惑的是,它每天只发生一次,从昨天开始,我不确定是什么造成的。 (系统已经存在,并且被我的客户使用,这种方法调用每天使用200-300次,我根本无法重现这种情况)
所以这是我的代码片段的情况,并按时间顺序链接到完整的代码
A用户想要创建一个新事务,将在控制器上调用此方法
def new
@penjualan = Penjualan.new
@penjualan.kode_transaksi = "J"+ DateTime.now.strftime("%d%m%Y%H%M%S")+@active_user.id.to_s
@customers = Customer.all(:limit => cookies[:limit], :order=>:kode_kustomer )
@barangs = Barang.all(:limit => cookies[:limit] )
respond_to do |format|
format.html # new.html.erb
format.json { render json: @penjualan }
end
end
在'新'视图中,我已使用:disable_with禁用了该按钮,因此用户无法单击提交按钮两次,从而阻止用户启动双POST请求
.row
.span4
= f.submit 'Proses', :class=>"btn btn-large btn-primary", :disable_with => "Processing..."
Submitted请求将在控制器上调用'create'方法,与#1控制器相同,此方法在1秒差异时调用两次。更奇怪的是,这个请求绕过了我在模型上定义的唯一性验证,它应该使第二个请求失败,因为第一个请求具有相同的kode_transaksi
我对我的模型(Penjualan)属性有独特的限制(kode_transaksi)
class Penjualan < ActiveRecord::Base
attr_accessible :customer_id, :jatuh_tempo, :kode_transaksi, :no_sj, :tanggal_bayar, :tanggal_transaksi, :total,:total_diskon, :ongkos, :user_id, :status_pembayaran, :is_returned, :kartu_kredit, :kartu_debit
has_many :detil_penjualans
attr_accessible :cash_total, :kembali
belongs_to :user
belongs_to :customer
validates :kode_transaksi, :uniqueness =>{:message=>"Transaksi Sudah Terjadi"}
scoped_search :on => [:kode_transaksi, :tanggal_transaksi, :status_pembayaran, :tanggal_bayar, :jatuh_tempo, :total ]
scoped_search :in => :customer, :on => [:nama_kustomer, :kode_kustomer]
scoped_search :in => :user, :on => [:username]
end
我的生产日志包含案例摘要
Started POST "/penjualans" for 192.168.1.104 at 2012-11-24 12:15:40 +0900
Processing by PenjualansController#create as HTML
Parameters: {.... too long, see below ....}
Started POST "/penjualans" for 192.168.1.104 at 2012-11-24 12:15:41 +0900
Processing by PenjualansController#create as HTML
Parameters: {..... too long, see below ....}
Redirected to url/penjualans/17403
Completed 302 Found in 378ms (ActiveRecord: 246.0ms)
Redirected to url/penjualans/17404
Completed 302 Found in 367ms (ActiveRecord: 233.8ms)
日志摘录http://pastebin.com/3tpua9gi
我对这种行为感到非常困惑,我的智慧结束了。任何帮助将不胜感激。
答案 0 :(得分:6)
为了快速解决问题,我建议您在模型之外为数据库添加一个唯一约束。
The rails docs suggest唯一性验证应该伴随数据库中的唯一约束,以防止两个连接同时插入相同唯一值的问题。
除此之外,用户是否可能快速连续双击表单?也许禁用表单无法正常工作,因此允许用户点击两次?
它是每天同一时间还是仅在特定时间?
答案 1 :(得分:2)
问题是由Rails中基于模型的唯一性约束的方式引起的。基本上,他们通过询问数据库是否存在具有约束的现有行并拒绝创建对象(如果是这种情况)来工作。
但是,考虑到常用的事务隔离级别(默认情况下通常是可重复读取),您可以使用重叠事务,这些事务都成功检查约束,然后在不知道彼此的情况下插入对象。
我认为,为了实现实际的唯一性,您有使用UNIQUE索引在数据库中定义约束。这比定义模型中的约束要重要得多,因为只有数据库能够通过检查约束来确保实际唯一性,因为在多线程/线程操作期间实际插入/更新了行。
关于你仍然想在Ruby中另外定义约束的唯一原因是它的错误消息更加友好,因此你可以处理常见的情况。如果数据库约束被命中,你只会在保存时得到一个错误而没有太多信息出错(但你仍然会有一个一致的数据库)