Hi,
I have a really simple Rails application that allows users to register their attendance on a set of courses. The ActiveRecord models are as follows:
class Course < ActiveRecord::Base
has_many :scheduled_runs
...
end
class ScheduledRun < ActiveRecord::Base
belongs_to :course
has_many :attendances
has_many :attendees, :through => :attendances
...
end
class Attendance < ActiveRecord::Base
belongs_to :user
belongs_to :scheduled_run, :counter_cache => true
...
end
class User < ActiveRecord::Base
has_many :attendances
has_many :registered_courses, :through => :attendances, :source => :scheduled_run
end
A ScheduledRun instance has a finite number of places available, and once the limit is reached, no more attendances can be accepted.
def full?
attendances_count == capacity
end
attendances_count is a counter cache column holding the number of attendance associations created for a particular ScheduledRun record.
My problem is that I don't fully know the correct way to ensure that a race condition doesn't occur when 1 or more people attempt to register for the last available place on a course at the same time.
My Attendance controller looks like this:
class AttendancesController < ApplicationController
before_filter :load_scheduled_run
before_filter :load_user, :only => :create
def new
@user = User.new
end
def create
unless @user.valid?
render :action => 'new'
end
@attendance = @user.attendances.build(:scheduled_run_id => params[:scheduled_run_id])
if @attendance.save
flash[:notice] = "Successfully created attendance."
redirect_to root_url
else
render :action => 'new'
end
end
protected
def load_scheduled_run
@run = ScheduledRun.find(params[:scheduled_run_id])
end
def load_user
@user = User.create_new_or_load_existing(params[:user])
end
end
As you can see, it doesn't take into account where the ScheduledRun instance has already reached capacity.
Any help on this would be greatly appreciated.