Ruby on rails 接受重复POST请求的Rails

Ruby on rails 接受重复POST请求的Rails,ruby-on-rails,ruby,post,Ruby On Rails,Ruby,Post,我的rails应用程序有一个奇怪的问题。我的应用程序在一秒钟内接受重复的POST请求 这个包含相同数据的重复请求奇怪地绕过了模型的唯一性验证。这将导致创建两行内容完全相同的数据 真正让我困惑的是,从昨天开始,这件事每天只发生一次,我不知道是什么原因造成的。(系统已经上线,我的客户正在使用,这个方法调用每天使用200-300次,我根本无法复制) 下面是我的代码snippent的情况,并按时间顺序链接到完整的代码 要创建新事务的用户将在控制器上调用此方法 def new @penjualan

我的rails应用程序有一个奇怪的问题。我的应用程序在一秒钟内接受重复的POST请求

这个包含相同数据的重复请求奇怪地绕过了模型的唯一性验证。这将导致创建两行内容完全相同的数据

真正让我困惑的是,从昨天开始,这件事每天只发生一次,我不知道是什么原因造成的。(系统已经上线,我的客户正在使用,这个方法调用每天使用200-300次,我根本无法复制)

下面是我的代码snippent的情况,并按时间顺序链接到完整的代码

  • 要创建新事务的用户将在控制器上调用此方法

    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  
    
    第648行的完整控制器

  • 在“新建”视图中,我禁用了带有:disable_with的按钮,这样用户就不能两次单击submit按钮,从而防止用户发起双重POST请求

    .row  
      .span4  
        = f.submit 'Proses', :class=>"btn btn-large btn-primary", :disable_with => "Processing..."
    
    第97行全视图

  • 提交的请求将在控制器上调用“create”方法,与#1相同的控制器,此方法在1秒差上调用两次。更奇怪的是,这个请求绕过了我在模型上定义的唯一性验证,在模型中,第二个请求与第一个请求具有相同的kode_transaksi,它应该会失败

  • 我的模型(Penjualan)属性(kode_transaksi)具有唯一性约束

  • 日志片段

  • 这种情况在我的数据库中创建了一个重复条目,从而导致问题

  • 我真的对这种行为感到困惑,我已经不知所措了。任何帮助都将不胜感激。

    为了快速解决问题,我建议您在模型之外为数据库添加一个独特的约束

    唯一性验证应伴随数据库中的唯一性约束,以防止两个连接同时插入相同的唯一值时出现问题

    除此之外,用户连续快速双击表单是否有问题?也许禁用表单不能正常工作,因此允许用户单击两次


    是每天都在同一时间还是只在特定时间?

    这个问题是由Rails中基于模型的唯一性约束的实现方式引起的。基本上,它们通过询问数据库是否存在给定唯一性约束的现有行,并拒绝创建对象(如果是这种情况)

    但是,考虑到常用的事务隔离级别(通常为可重复读取),您可以有重叠的事务,这两个事务都成功地检查了约束,然后插入了它们的对象,而彼此都不知道

    这是因为为了实现实际的唯一性,必须使用
    UNIQUE
    索引在数据库中定义约束。这比在模型中定义约束要重要得多,因为只有数据库能够通过检查约束来确保实际的唯一性,因为在多线程操作期间实际插入/更新了一行

    您仍然希望在Ruby中另外定义约束的唯一原因是它的错误消息更加友好,因此您可以处理常见情况


    如果命中的是数据库约束,而不是Rails约束,那么在调用
    save
    时,您只会返回
    false
    ,而没有太多信息,除了失败的数据库约束之外,还有什么问题。不过,好处是保证以后仍然有一个一致的数据库。

    Hmm,我现在将向数据库添加约束。它只发生过两次,今天和昨天,似乎是随机发生的。这个系统已经在生产模式上运行了两个月,并且没有进行任何修改,这种情况真的让我很困惑。是的,真的很奇怪。。约束应该可以防止问题再次出现,但可能需要关注日志以查看是否再次发生。也可能是由于某种随机的机会,一个请求被发送到web服务器中的两个工作进程。。不知道怎么会发生这种情况,但谁知道呢..Nginx在作为反向代理(例如在Thins或Unicorns前面)工作时,有时会在后端出现某些错误时将请求重新分派给。违反了RFC2616,它甚至对绝对不打算重新发布的POST和PUT请求也这样做。。。因此,您必须确保您的DB约束是合理的。明天将返回这里并发布结果,感谢您响应@tigraineading Unique constraints解决了问题,尽管看到了日志,但仍在发出双重post请求。可能是因为Holger刚才解释的,希望有个问题可以,如果您将create封装在事务中并使用某种db锁,会解决问题吗?不是说这是一个更好的解决方案,只是想知道它是否有效。@244an这或多或少是事务所做的。虽然您可以手动完成这项工作,但为您的需要选择合适的事务隔离级别(基本上是一致性和性能之间的折衷)并定义所需的数据约束可能更容易(而且性能更高)。在旧版本的:disable_with中,“onclick”中有一个“this.form.submit”在Rails生成的html中,如果使用:disable_with。不知道它是否仍然是这样,或者它是否可以解释你的问题。如果用户提交而不是点击按钮,我认为表单无论如何都会提交(虽然它没有被禁用)。如果他们使用或单击“提交”按钮,会有区别吗?
    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)