销毁记录,而不是在表单嵌套模型中进行更新

时间:2019-02-18 23:50:36

标签: ruby-on-rails activerecord ruby-on-rails-5 nested-forms

我有一个模型opening_times记录着商店的营业时间。

create_table "opening_times", force: :cascade do |t|
    t.string "day"
    t.time "morning"
    t.time "evening"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.bigint "shop_id"
    t.index ["shop_id"]
  end

仅通过edit控制器的shops操作中的嵌套形式来更新此模型。我没有opening_times控制器。

然后基本上可以做的事情非常有限:update操作。

尽管我有一个问题:当过去某一天有开放时间时,假设是星期二,并且用户希望该天不工作,则用户同时填写morning和{{1 }}空白。

我可以在数据库中保存空值,但是最好在星期二删除记录。

然后在模型文件中设置以下内容:

evening

但这不起作用。

是否可以删除打算在模型级别更新的记录?

3 个答案:

答案 0 :(得分:1)

我认为您最好为此操作创建某种维护脚本。就像耙任务之类的。因此,定期运行一个简单的查找并销毁:

OpeningTime.where(morning:nil, evening:nil).destroy_all

只需每天或每周运行一次以清理数据库,并且在保存时不必理会记录。

我认为您当前代码的问题是您要删除before_save中的记录,因此会产生两个问题:

1 /如果这不是一个持久记录,而是一个新记录,rails应该怎么做?销毁将失败,并且整个事务将回滚(请查看您的控制台)

2 /即使记录是持久性的,删除记录也可以,但是接下来将执行的保存操作将失败,从而导致回滚。

答案 1 :(得分:1)

有一个Rails方式可以解决这个问题。它可以很容易地完成,但是您需要从Shop模型中完成。在该模型中插入:

class Shop < ApplicationRecord
  accepts_nested_attributes_for :opening_times, allow_destroy: true, reject_if: :reject_opening_time?

  def reject_opening_time?(attributes)
    persisted = attributes[:id].present?
    time_values = attributes.slice(:morning, :evening).values
    without_time = time_values.any?(&:blank?)
    attributes.merge!(_destroy: true) if persisted and without_time
    without_time && !persisted # Return false so as to reject new opening_time if any time attributes are empty
  end
end

现在,对于每个opening_time嵌套记录,Rails都会评估时间属性。如果任何时间值为空,它将适当地处理记录。如果记录是持久的,它将添加一个_destroy属性,当您保存父记录时,该属性将破坏嵌套的记录。如果该记录没有保留,则在保存父记录时,记录将被拒​​绝(忽略)。

答案 2 :(得分:0)

如果您宁愿没有morningevening带有空值的字段,为什么不仅仅验证这些字段的存在呢?然后,使用外部方法验证这种情况会更加清洁。

首先,应将其放在Shop模型中:

validates_associated :opening_times

此代码将确保您的关联在插入/更新之前已通过验证

现在您可以在OpeningTime模型中进行验证,如下所示:

validates :morning, :evening, presence: true

如果您只是想在更新操作中这样做,甚至可以:

validates :morning, :evening, presence: true, on: :update

如果您希望至少显示一个值,也可以使用:

validate :morning_and_evening_validation

def morning_and_evening_validation
  morning.present? || evening.present?
end

我认为大多数情况下它更清晰易读。