before_save如果attribute.present?

before_save if attribute.present?

before_save :date_started_sets_deadline, if date_started.present?

如果 :date_started == nil,我不希望这个 before_save 到 运行。我已经尝试了上述行的各种版本,所以不确定是否必须更改它或方法本身。

def date_started_sets_deadline
  if self.date_started > Date.tomorrow
    self.deadline = self.date_started
  end
end

每当用户尝试在没有 date_started

的情况下创建挑战时,我正在努力避免错误 NoMethodError (undefined method '>' for nil:NilClass): app/models/challenge.rb:35:in 'date_started_sets_deadline'

一种方法是在方法中加入条件 if。

def date_started_sets_deadline
  if self.date_started != nil 
    if self.date_started > Date.tomorrow
     self.deadline = self.date_started
    end
  end
end

编辑

试试这个,我在个人项目上检查过。

before_save :date_started_sets_deadline, if: self.date_started.present?

before_save 语句更改为以下内容:

before_save :date_started_sets_deadline, if: :date_started?

如果您向 if 提供 symbol,则 rails 对其求值 在实例的上下文中。通过添加?,它是一个自动生成的方法,本质上与date_started.present?

相同

此外,如果在 date_started_sets_deadline 实现中需要 date_started,我还会显式添加检查,而不是仅仅依赖于在回调逻辑中添加 if 条件。

def date_started_sets_deadline
  if self.date_started.present? && (self.date_started > Date.tomorrow)
    self.deadline = self.date_started
  end
end

有关详细信息,请参阅 Using :if and :unless with a Symbol

另一个答案提到提供要调用的符号,我建议创建您自己的方法作为该符号,以便您可以包含您感兴趣的所有条件,即。

before_save :set_deadline, if: :starts_after_tomorrow?

def starts_after_tomorrow?
  date_started? && date_started > Date.tomorrow
end

def set_deadline
  self.deadline = date_started
end

我认为这比在 before_save 和 setter 中重复逻辑更清晰。

您可以在回调方法中检查条件和更改数据。

before_save :date_started_sets_deadline

def date_started_sets_deadline
  if date_started.present? && self.date_started > Date.tomorrow
   self.deadline = self.date_started
  end
end

但我认为分担这些责任是个好主意。例如,您可以将检查移动到另一个方法中。

before_save :set_deadline, if: :set_deadline?

def set_deadline?
  date_started.present? && date_started > Date.tomorrow
end

def set_deadline
  self.deadline = date_started
end

对于简单的条件,很难找到好的方法名,或者感觉有点过度设计,所以你可以直接在回调定义中使用 procs 和 lambdas 检查它。但是你要小心使用。

before_save :set_deadline, if: ->() { date_started.present? }

def set_deadline
  self.deadline = date_started if self.date_started > Date.tomorrow
end