Rails refactor/combine 相似before_update 回调方法合二为一
Rails refactor/combine similar before_update callback methods into one
我创建了一些模型回调方法,在每次创建、更改或删除文件时为属性添加时间戳。
我想知道是否有更优雅的方式来编写这些回调,而不必重复类似的方法代码五次:
before_update :quote_file_updated?, on: [:create, :update], if: ->(r) { r.quote_file_changed? }
before_update :survey_file_updated?, on: [:create, :update], if: ->(r) { r.survey_file_changed? }
before_update :sign_off_sheet_file_updated?, on: [:create, :update], if: ->(r) { r.sign_off_sheet_file_changed? }
before_update :invoice_file_updated?, on: [:create, :update], if: ->(r) { r.invoice_file_changed? }
before_update :cert_file_updated?, on: [:create, :update], if: ->(r) { r.cert_file_changed? }
def quote_file_updated?
self.remove_quote_file ? self.quote_file_date = nil : self.quote_file_date = Time.now
end
def survey_file_updated?
self.remove_survey_file ? self.survey_file_date = nil : self.survey_file_date = Time.now
end
def sign_off_sheet_file_updated?
self.remove_sign_off_sheet_file ? self.sign_off_sheet_file_date = nil : self.sign_off_sheet_file_date = Time.now
end
def invoice_file_updated?
self.remove_invoice_file ? self.invoice_file_date = nil : self.invoice_file_date = Time.now
end
def cert_file_updated?
self.remove_cert_file ? self.cert_file_date = nil : self.cert_file_date = Time.now
end
before_update :set_updated_fields, on: [:create, :update]
def set_updated_fields
["quote", "survey", "sign_off_sheet", "invoice", "cert"].each do |filetype|
if self.send("#{filetype}_file_changed?")
self.attributes = {"#{filetype}_file_date" => self.send("remove_#{filetype}_file") ? nil : Time.now}
end
end
end
这有点难以理解,但我认为它会起作用。
在这种情况下,最好让代码保持冗长,因为很难看出发生了什么。应更改回调,以便 before_update
变为 before_save
(因此它也在创建操作中触发)。
回调应该是:
before_save :quote_file_updated?, if: ->(r) { r.quote_file_changed? or r.remove_quote_file.to_b }
to_b
是一种将 0
或 1
从 remove_quote_file
转换为布尔值的方法。基于此我们可以在删除文件时将日期戳设置为nil
。
方法本身应该变成:
def quote_file_updated?
remove_quote_file.to_b ? self.quote_file_date = nil : self.quote_file_date = Time.now
end
我们再次执行类似的操作,将 remove_quote_file
评估为布尔值,然后基于此更新或删除时间戳。
我创建了一些模型回调方法,在每次创建、更改或删除文件时为属性添加时间戳。
我想知道是否有更优雅的方式来编写这些回调,而不必重复类似的方法代码五次:
before_update :quote_file_updated?, on: [:create, :update], if: ->(r) { r.quote_file_changed? }
before_update :survey_file_updated?, on: [:create, :update], if: ->(r) { r.survey_file_changed? }
before_update :sign_off_sheet_file_updated?, on: [:create, :update], if: ->(r) { r.sign_off_sheet_file_changed? }
before_update :invoice_file_updated?, on: [:create, :update], if: ->(r) { r.invoice_file_changed? }
before_update :cert_file_updated?, on: [:create, :update], if: ->(r) { r.cert_file_changed? }
def quote_file_updated?
self.remove_quote_file ? self.quote_file_date = nil : self.quote_file_date = Time.now
end
def survey_file_updated?
self.remove_survey_file ? self.survey_file_date = nil : self.survey_file_date = Time.now
end
def sign_off_sheet_file_updated?
self.remove_sign_off_sheet_file ? self.sign_off_sheet_file_date = nil : self.sign_off_sheet_file_date = Time.now
end
def invoice_file_updated?
self.remove_invoice_file ? self.invoice_file_date = nil : self.invoice_file_date = Time.now
end
def cert_file_updated?
self.remove_cert_file ? self.cert_file_date = nil : self.cert_file_date = Time.now
end
before_update :set_updated_fields, on: [:create, :update]
def set_updated_fields
["quote", "survey", "sign_off_sheet", "invoice", "cert"].each do |filetype|
if self.send("#{filetype}_file_changed?")
self.attributes = {"#{filetype}_file_date" => self.send("remove_#{filetype}_file") ? nil : Time.now}
end
end
end
这有点难以理解,但我认为它会起作用。
在这种情况下,最好让代码保持冗长,因为很难看出发生了什么。应更改回调,以便 before_update
变为 before_save
(因此它也在创建操作中触发)。
回调应该是:
before_save :quote_file_updated?, if: ->(r) { r.quote_file_changed? or r.remove_quote_file.to_b }
to_b
是一种将 0
或 1
从 remove_quote_file
转换为布尔值的方法。基于此我们可以在删除文件时将日期戳设置为nil
。
方法本身应该变成:
def quote_file_updated?
remove_quote_file.to_b ? self.quote_file_date = nil : self.quote_file_date = Time.now
end
我们再次执行类似的操作,将 remove_quote_file
评估为布尔值,然后基于此更新或删除时间戳。