Reputation: 8063
I have two models:
The lecture has a capacity and a waiting list. If there's an enrollment for a lecture, I'd like to validate if there are free seats available.
Created two helpers for that:
def availableSeats
return self.capacity - self.enrollments.confirmedEnrollments.count
end
def waitListAvailable
return self.waitListCapacity - self.enrollments.waitList.count
end
I thought about having the checks in the enrollment-controller, but it doesn't work.
if(@lecture.availableSeats <= 0)
if(@lecture.waitListAvailable <= 0)
flash[:error] = "Enrolment not possible as the waiting list is full."
# interrupt and don't save, but how?
else
flash[:warning] = "You are on the waiting list."
@enrollment.confirmed = nil
end
else
@enrollment.confirmed = DateTime.now
end
Any ideas how this would work?
Upvotes: 0
Views: 454
Reputation: 8063
Thanks edgerunner for the answer! I found another, easy solution:
validate do |enrollment|
if(enrollment.lecture.availableSeats <= 0)
enrollment.errors.add_to_base("This lecture is booked out.") if enrollment.lecture.waitListAvailable <= 0
end
end
The warnings for the waiting list are handled in the controller:
if @enrollment.save
if @enrollment.confirmed?
format.html { redirect_to(@lecture, :notice => 'Enrollment successfull.') }
format.xml { render :xml => @lecture, :status => :created, :location => @lecture }
else
format.html { redirect_to(@lecture, :alert => 'You're on the waiting list!') }
format.xml { render :xml => @lecture, :status => :created, :location => @lecture }
end
Upvotes: 0
Reputation: 14973
I'm assuming that your Enrollment model defines both the accepted students and those on the waiting list. I'm also assuming that the Lecture model has two attributes available_seats
and available_wait_space
, and the wait list is populated on a first-come basis and students are declined if the list is full, but the actual seats are confirmed or rejected by the lecturer manually.
I'd certainly advise against doing anything at the controller level. This is a job for the models only.
class Enrollment < ActiveRecord::Base
belongs_to :student
belongs_to :lecture
validates_presence_of :student_id, :lecture_id, :status
validates_inclusion_of :status, :in => %w[waiting confirmed rejected]
validate :must_fit_in_wait_list, :on => :create
validate :must_fit_in_class, :on => :update
scope :waiting, where(:status => 'waiting')
scope :confirmed, where(:status => 'confirmed')
scope :rejected, where(:status => 'rejected')
def must_fit_in_wait_list
unless waiting.count < lecture.available_wait_space
errors.add(:base, "The waiting list is full")
end
end
def must_fit_in_class
unless confirmed.count < lecture.available_seats
errors.add(:status, "The seats are full")
end
end
end
By the way, don't forget to set the default value for status
to "waiting" in your migrations.
Upvotes: 1
Reputation: 2011
I think this is best handled in the model. I've had a similar issue in a question I posed previously
Validating :inclusion in rails based on parent Model's attribute value
Upvotes: 0