More `touch` option for belongs_to?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

More `touch` option for belongs_to?

Leonardo Wong
Hi,

I am facing a racing conditions in `touch`. Let me use this example to explain:

class Order < ApplicationRecord
  has
_many :items
end

class Item < ApplicationRecord
 
belongs_to :order, touch: true
  # More relationship:
  # belongs_to :other_model, touch: true
  # belongs_to :other_model_2, touch: true
  # has_many :other_model_3
end

For example, I have a one to many relationship, Order has many Items. When an Item get update, it `touch` Order.
Order table has `lock_version` column, which means Optimistic Locking is enabled.

When some logic update an Item, the relationship will auto trigger `touch` Order, which has a chance that StaleObjectError error being raised.

The problem is here, coding which modify Item is everywhere. Implement a rescue/retry logic manually in all the places is not a possible solution...
There are many relationship in my project having this `touch` mechanism. Some of them are even a chain: A touch B touch C touch D.
However, I always have a clear answer in my mind of the question: How important is the touch?
  1. very important, need retry until success.
  2. accuracy is not that important (updated_at datetime value). In this case, if it raise StaleObjectError error, which means someone else has updated the record, right before my touch. So my touch can actually skip.
I can write some workaround code like:
class Item < ApplicationRecord
  
belongs_to :order
  # More relationship:
  # belongs_to :other_model
  # belongs_to :other_model_2
  # has_many :other_model_3

  after_commit :touch_all_belongs_to_models

  def 
touch_all_belongs_to_models
    [order, 
other_model, other_model_2].each do |model|
      begin
        model.touch
      rescue ActiveRecord::StaleObjectError
        begin
          # Reload lock_version in particular.
          reload
        rescue 
ActiveRecord::RecordNotFound
          # if the record is gone there is nothing to do.
        else
          retry
        end
            end
    end
  end
end
Which basically I write my own touch, don't use Rails build-in solution. A lot more complex.

So I am thinking, maybe we can have more options for touch? Something like:
belongs_to :order, touch: :retry # retry until success.

belongs_to :order, touch: :soft # skip touch if StableObjectError is raise, other modification of records should still save to DB.

PS: Sorry for my poor english.

Thanks,
Leonardo

--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/rubyonrails-core.
For more options, visit https://groups.google.com/d/optout.