问题
The code works fine in detecting overlapping dates to not save a Booking if it already exist for a given Room. However, I had to twist my code to make it work because validation would make the update
in my controller not valid instead of the save
. So I want to know what is wrong with my code as normally the not valid should apply to the save and not the update.
In fact, to tell me that a booking cannot be saved instead of throwing an error, it just did not update the booking.end_date in my contoller while it should raise an error when it save and not when I try to update it:
I have a controller that create a new booking for a room (this is what I want to improve):
def create_book_now
@room = Room.find(params[:room_id])
booking = @room.bookings.build(booking_params)
if booking.save #I want to not save if model validation are not OK
if @room.bookings.last.update(end_date: booking.start_date + booking.length.days) # I have to check if this is true for my validation to work, I am sure it is not normal
flash[:notice] = "Booking done"
redirect_to root_path
else
flash[:error] = "booking.errors.full_messages.first if booking.errors.any?"
redirect_to room_book_now_path(@room.id)
end
else
flash[:error] = booking.errors.full_messages.first if booking.errors.any?
redirect_to room_book_now_path(@room.id)
end
end
The new booking go through validation to make sure no booking with overlapping date has been made:
class Booking < ActiveRecord::Base
belongs_to :room
validates :length, :presence => true
validate :dates_are_available
def dates_are_available
room = Room.find(self.room_id)
# if Room.find(self.room_id).bookings.exists?
# self.errors.add(:base, 'Date already taken')
# end
conditions = []
conditions << '(start_date >= :new_start_date AND end_date >= :new_end_date)'
conditions << '(start_date >= :new_start_date AND end_date <= :new_end_date)'
conditions << '(end_date BETWEEN :new_start_date AND :new_end_date)'
conditions << '(start_date <= :new_start_date AND end_date >= :new_end_date)'
if room.bookings.where(conditions.join(' OR '), new_start_date: self.start_date, new_end_date: self.end_date).exists?
self.errors.add(:base, 'Date already taken')
return false
end
end
end
So my question is how to make my code in my controller better so that the validation will work when Booking is saved and not when it is updated
回答1:
You can do something like that, check all bookings that you assing to your room before save, and one by one check the condition.
def dates_are_available
room.bookings.each do |b|
if bookings.start_date
self.errors.add(:base, 'Date already taken')
end
end
end
来源:https://stackoverflow.com/questions/29551261/rails-code-readability-for-my-validation