rails自定义验证无法识别

时间:2015-04-09 15:19:58

标签: ruby-on-rails validation ruby-on-rails-4 model-view-controller

如果预订已经存在,我想运行会返回错误消息的验证。

最新更新

  

它有效,但它引导我一个带有更新工作代码的新问题:   Rails code readability for my validation

状态更新

  

当房间已经预订时,它会触发验证roll_back   (已经是一个开始)但现在我想找出一个代码,只有它   日期重叠时的roll_back,而不仅仅是因为有预订。

这是我的架构:

  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

2 个答案:

答案 0 :(得分:1)

如果DateBooking模型的目的只是为了测试您是否创建了Bookingstart_date + length组合与现有Booking重叠{1}},那么您不需要此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

答案 1 :(得分:0)

感谢@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