问题
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"
回答1:
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?
来源:https://stackoverflow.com/questions/26541182/validates-overlap-gem-multiple-scopes-overwriting-eachother