Rails accepting repeated POST requests

I have a strange problem with my rail application. My application accepts repeated POST requests within one second

This duplicate request containing the same data is strangely able to bypass the authentication of my model. This results in two rows of data with the same content.

What really puzzled me was that it only happens once a day, starting yesterday, I'm not sure what caused it. (The system is already running and is being used by my clients, this method call is used 200-300 times a day, and I cannot reproduce it at all)

So, here is the situation with my code snippet and a link to the complete code with chronological order

  • A users want to create a new transaction, call this method on the controller

    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 

    full controller at http://pastebin.com/Lmp7hncn line 648

  • In the "new" view, I disabled the button with: disable_with, so the user cannot double-click the submit button, preventing the user-initiated double POST request

     .row .span4 = f.submit 'Proses', :class=>"btn btn-large btn-primary", :disable_with => "Processing..." 

    full view http://pastebin.com/7b9W68RY line 97

  • The submitted request will call the create method on the controller, the same controller as # 1. This method is called twice with a difference of 1 second. Even stranger is that this request bypasses the uniqueness check that I defined in the model, where it is assumed that the second request in order to have the same transax_code as the first request

  • I have uniqueness restrictions for the attributes of my model (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 
  • My Production Magazine with Case Fragment

     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) 

Fragment of magazines http://pastebin.com/3tpua9gi

  • This situation created a duplicate entry in my database that causes the problem

I am really puzzled by this behavior, and I am on my way. Any help would be greatly appreciated.

+4
source share
2 answers

To quickly fix the problem, I suggest that you add a unique constraint to the database other than the model.

The docs rails suggest that the uniqueness check should be followed by a unique constraint in the database to prevent problems with two connections by inserting the same unique value at the same time.

In addition, maybe the problem of double-clicking on the form in quick succession? Maybe disabling the form does not work correctly and therefore allows users to double-click?

Is it every day at the same time or only at a specific time?

+6
source

The problem is that Rails implements model-based uniqueness restrictions. Basically, they work by querying the database if there are any existing rows with the attribute and refuse to create the object, if so.

However, given the frequently used transaction isolation levels (usually repeated by default), you may have overlapping transactions that successfully check the constraint and then insert their objects without knowing each other.

This is because, to achieve real uniqueness, you have to define a constraint in the database using UNIQUE indexes. This is much more important than defining constraints in your model, since only the database is able to provide real uniqueness by checking the constraint, since the row is actually filled / updated during the operation with several / threads.

The only reason you still want to further define the restriction in Ruby is that its error messages are much more friendly, and therefore you can handle the usual case. If the database restriction is removed, you just get a false value to save without much information about what went wrong (but you will still have a consistent database)

+2
source

All Articles