2

I'm using Validates_Overlap Gem which can be found here: https://github.com/robinbortlik/validates_overlap

The essence is I have two rooms that can be booked. I want the validation to step in when the same room already has a CONFIRMED booking in the SAME room. It shouldn't throw me an error when the other room is booked, or if the same room is booked but hasn't been confirmed.

My code so far is as follows

validates :start_time, :end_time, 
    :overlap => {
        :exclude_edges => ["starts_at", "ends_at"],
        :scope => { "bookings.studio_id" => proc {|booking| booking.studio_id}} &&  { "bookings.is_confirmed" => proc {|booking| booking.is_confirmed == true}}
        }, on: :update

This returns the following from my server:

Booking Exists (0.4ms)  SELECT  1 AS one FROM "bookings"  WHERE ((bookings.end_time IS NULL OR bookings.end_time >= '2014-10-23 20:00:00.000000') AND (bookings.start_time IS NULL OR bookings.start_time <= '2014-10-24 03:00:00.000000') AND bookings.id != 9 AND bookings.is_confirmed  = 't') LIMIT 1

There are two other bookings (with this studio_id) and none of them are confirmed. What gives?

Here are all the bookings with :studio_id => 2

[#<Booking id: 1, studio_id: 2, engineer_id: 5, is_confirmed: false, title: "", allDay: false, created_at: "2014-10-23 19:59:01", updated_at: "2014-10-23 19:59:01", start_time: "2014-10-23 19:00:00", end_time: "2014-10-23 21:00:00", user_id: nil, booker: "Client", client_id: 3>,
 #<Booking id: 8, studio_id: 2, engineer_id: 1, is_confirmed: false, title: "", allDay: false, created_at: "2014-10-24 03:07:34", updated_at: "2014-10-24 03:07:34", start_time: "2014-10-23 19:00:00", end_time: "2014-10-23 22:00:00", user_id: nil, booker: "Pat Sullivan", client_id: nil>,
 #<Booking id: 9, studio_id: 2, engineer_id: 2, is_confirmed: false, title: "", allDay: false, created_at: "2014-10-24 03:26:17", updated_at: "2014-10-24 03:26:17", start_time: "2014-10-23 20:00:00", end_time: "2014-10-24 03:00:00", user_id: nil, booker: "Client", client_id: 4>]

Update I noticed that the studio_id isn't being noticed with the && in the scope line. How can I have the scope register both? Can I do it within the scope line or should I create a method?

I've also tried a simpler

    validates :start_time, :end_time, 
    :overlap => {
        :exclude_edges => ["starts_at", "ends_at"],
        :scope => "is_confirmed" && "studio_id"
        }, on: :update

This does the same thing -- only uses the later "studio_id"

Peege151
  • 1,562
  • 2
  • 21
  • 45

1 Answers1

3

I know, that the names of options are confusing and I'm sorry for that.

I suggest you to implement your named scope called :confirmed and pass it as :query_option parameter.

I think, it should look like this:

class Booking < ActiveRecord::Base
  scope :confirmed_scope, -> {confirmed: true}  
  validates :start_time, :end_time, :overlap => {
    :exclude_edges => ["starts_at", "ends_at"],
    :scope => "studio_id",
    :query_options => {:confirmed_scope => nil}
    }, on: :update
end

BTW... be careful if you are using Rails 4.1, there is a change https://github.com/robinbortlik/validates_overlap#rails-41-update

Short explanation: what you pass as a :scope option, this behave like attribute. But you can extend it by :query_options. What is inside query options will be called in the query chain. So internally it will be called like this:

Booking.confirmed_scope.where("starts_at > 18-02-2014 AND ends_at < 20-02-2014 AND studio_id = 1")

Is it more clear now?

Robin Bortlík
  • 740
  • 7
  • 15