我有一个模型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
但这不起作用。
是否可以删除打算在模型级别更新的记录?
答案 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)
如果您宁愿没有morning
和evening
带有空值的字段,为什么不仅仅验证这些字段的存在呢?然后,使用外部方法验证这种情况会更加清洁。
首先,应将其放在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
我认为大多数情况下它更清晰易读。