rails 无法识别自定义验证
rails custom validation not recognized
我想运行验证如果预订已经存在,将return一条错误消息。
最新更新
It works but it leads me to a new question with updated working code:
Rails code readability for my validation
状态更新
It triggers validation roll_back when the room already has a Booking
(already a start) BUT now I want to figure out a code so that it only
roll_back when dates overlaps and not just because there is a booking.
这是我的架构:
create_table "bookings", force: :cascade do |t|
t.datetime "start_date"
t.datetime "end_date"
t.integer "length"
t.integer "room_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "rooms", force: :cascade do |t|
t.string "name"
t.string "type_room"
t.integer "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
除了预订模式我的联想:
class Room < ActiveRecord::Base
has_many :bookings
end
提前谢谢大家的帮助。安托万
更新控制器
def create_book_now
@room = Room.find(params[:room_id])
#Save booking in DB if model validation are OK
booking = @room.bookings.build(booking_params)
if booking.save
booking.update(end_date: booking.start_date + booking.length.days)
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
end
更新模型
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_date
如果 DateBooking
模型的目的只是为了测试您是否没有使用 start_date
+ length
组合创建一个 Booking
现有 Booking
,那么您不需要此 DateBooking
模型:
class Booking < ActiveRecord::Base
validate :dates_are_available
def dates_are_available
conditions = []
conditions << '(start_date BETWEEN :new_start_date AND :new_end_date)' # the new range contains an already existing start_date
conditions << '(end_date BETWEEN :new_start_date AND :new_end_date)' # the new range contains an already existing end_date
conditions << '(start_date <= :new_start_date AND end_date >= :new_end_date)' # the new range contains an already existing range start_date..end_date
if Booking.where(conditions.join(' OR '), new_start_date: self.start_date, new_end_date: self.end_date).exists?
self.errors.add(:base, 'Date already taken')
end
end
编辑,新尝试:
def dates_are_available
conditions = []
conditions << '(end_date BETWEEN :new_start_date AND :new_end_date)'
conditions << '(start_date <= :new_start_date AND end_date >= :new_end_date)'
if Booking.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
感谢@MrYoshiji 的贡献,我在他的代码中添加了 room_id
信息和更多 SQL 以涵盖所有可能的日期重叠。这是对我有用的:
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)
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
我想运行验证如果预订已经存在,将return一条错误消息。
最新更新
It works but it leads me to a new question with updated working code: Rails code readability for my validation
状态更新
It triggers validation roll_back when the room already has a Booking (already a start) BUT now I want to figure out a code so that it only roll_back when dates overlaps and not just because there is a booking.
这是我的架构:
create_table "bookings", force: :cascade do |t|
t.datetime "start_date"
t.datetime "end_date"
t.integer "length"
t.integer "room_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "rooms", force: :cascade do |t|
t.string "name"
t.string "type_room"
t.integer "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
除了预订模式我的联想:
class Room < ActiveRecord::Base
has_many :bookings
end
提前谢谢大家的帮助。安托万
更新控制器
def create_book_now
@room = Room.find(params[:room_id])
#Save booking in DB if model validation are OK
booking = @room.bookings.build(booking_params)
if booking.save
booking.update(end_date: booking.start_date + booking.length.days)
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
end
更新模型
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_date
如果 DateBooking
模型的目的只是为了测试您是否没有使用 start_date
+ length
组合创建一个 Booking
现有 Booking
,那么您不需要此 DateBooking
模型:
class Booking < ActiveRecord::Base
validate :dates_are_available
def dates_are_available
conditions = []
conditions << '(start_date BETWEEN :new_start_date AND :new_end_date)' # the new range contains an already existing start_date
conditions << '(end_date BETWEEN :new_start_date AND :new_end_date)' # the new range contains an already existing end_date
conditions << '(start_date <= :new_start_date AND end_date >= :new_end_date)' # the new range contains an already existing range start_date..end_date
if Booking.where(conditions.join(' OR '), new_start_date: self.start_date, new_end_date: self.end_date).exists?
self.errors.add(:base, 'Date already taken')
end
end
编辑,新尝试:
def dates_are_available
conditions = []
conditions << '(end_date BETWEEN :new_start_date AND :new_end_date)'
conditions << '(start_date <= :new_start_date AND end_date >= :new_end_date)'
if Booking.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
感谢@MrYoshiji 的贡献,我在他的代码中添加了 room_id
信息和更多 SQL 以涵盖所有可能的日期重叠。这是对我有用的:
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)
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