【问题标题】:rails custom validation not recognizedrails 自定义验证无法识别
【发布时间】:2015-06-15 01:24:49
【问题描述】:

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

最新更新

它可以工作,但它会导致我使用更新的工作代码提出一个新问题: Rails code readability for my validation

状态更新

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

这是我的架构:

  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 而不是抛出错误

【问题讨论】:

  • 你的意思是你的验证没有被执行?你怎么知道的?
  • 首先,我不会在模型本身中处理重定向……那应该在控制器中。无论如何,您可以添加logger.debug 'in validation' 以查看您的验证是否被调用?
  • 我知道它没有被执行,因为重定向没有发生,我看到记录保存在数据库中。我故意尝试创建一个应该让验证工作的记录。
  • 我的控制器一定有问题吗?我应该告诉控制器它必须在创建预订时运行验证?
  • 您的 validate_existing_dates 的 if 语句可能无法正常工作。在 if 语句后添加 binding.pry,看看它是否真的正确触发。

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


【解决方案1】:

如果DateBooking 模型的目的只是为了测试您是否没有使用不与现有Booking 重叠的start_date + length 组合来创建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

【讨论】:

  • 我试过你的代码,我只是把它粘贴到我的模型中,它不起作用。预订保存在数据库中,它完全忽略了验证
  • 在我的控制器中,我现在尝试在保存之前验证它是否有效,但我最终遇到了同样的问题
  • 你说得对,我不需要 DateBooking 模型来验证日期。我已经更新了我的控制器并清理了它。
  • 现在我想弄清楚如何让你的代码工作
  • 当房间已经有预订时,我设法触发验证回滚(酷)但现在我想找出一个代码,以便它只在日期重叠时回滚,而不仅仅是因为有一个预订。
【解决方案2】:

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

【讨论】:

  • 我尝试了这个以满足我的要求之一。它运作良好,但在两种情况下对我没有帮助。 First-> 如果数据库中存在的任何记录中的 new_start_date 和 new_end_date 小于 start_date 和 end_date,则不允许我保存记录。第二 -> 如果我尝试更新而不是创建,那么它也不允许我保存相同的记录。不知道有没有道理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-04
相关资源
最近更新 更多