Rails: How to limit number of items in has_many association (from Parent)

后端 未结 8 1085
情深已故
情深已故 2021-01-30 11:45

I would like to limit the number of items in an association. I want to ensure the User doesn\'t have more than X Things. This question was asked before and the solution had th

8条回答
  •  孤独总比滥情好
    2021-01-30 12:08

    I thought I'd chime in here. It seems like most of the answers here fail under race-conditions. I'm trying to limit the number of users who can sign up at a certain price point in our app. Checking the limit in Rails means that 10 simultaneous registrations could get through, even if it exceeds the limit I'm trying to set.

    For example, say I want to restrict registrations to no more than 10. Let's say that I already have 5 users registered. Let's also say that 6 new users attempt to register at the same time. In 6 different threads, Rails reads the number of slots remaining, and it gets the answer 5. This passes validation. Rails then allows all registrations to go through, and I have 11 registrations. :/

    Here's how I solved this problem:

    def reserve_slot(price_point)
      num_updated = PricePoint.where(id: price_point.id)
        .where('num_remaining <= max_enrollments')
        .update_all('num_remaining = num_remaining + 1')
    
      if num_updated == 0
        raise ActiveRecord::Rollback
      end
    end
    

    Using this approach, I never allow more registrations than max_enrollments, even when the app is under load. This is because the validation and increment is done in a single, atomic database operation. Note, too that I always call this method from within a transaction, so it rolls back under failure.

提交回复
热议问题