繁体   English   中英

rails 5 仅在当前为 nil 时才更新属性

[英]rails 5 update attribute only if it's currently nil

Rails 5 中使用 activerecord 更新属性的首选方式是什么,仅当它当前为零时。

car = Car.first
car.connected_at = Time.zone.now
car.save

OR

car = Car.first
car.update!(connected_at: Time.zone.now)


it should update only if car.connected_at is nil

你可以简单地检查#nil?

car = Car.first
car.update_attribute(:connected_at, Time.zone.now) if car.connected_at.nil?

这还不够通用。 我想要 before_validation 之类的东西。我只是不确定哪种方式是首选。

好吧,如果你想进行验证,它看起来像这样..

before_save :validate_connected_at

private

def validate_connected_at
  connected_at = connected_at_was if connected_at_changed? && connected_at_was.present?
end

或者

before_save :set_connected_at

private

def set_connected_at
  connected_at = Time.zone.now if connected_at.nil?
end

如您所见,更多检查,更多方法。 我肯定会去第一个。

但是,如果您想添加错误消息,那么这就是方法

errors.add(:connected_at, 'Already present!')

那么“#{attr}_was”在 before_save 方法中所有定义的属性上总是可用的?

它们通常可用,而不仅仅是在before_save ,例如在控制台中..

car = Car.first
car.connected_at
=> 'some value'
car.connected_at = 'some other value'
car.connected_at
=> 'some other value'
car.connected_at_was
=> 'some value'

听起来您是在说您想修改特定属性的工作方式,以便它悄悄地忽略您。 我认为你为什么要封闭它的本能是合理的,但如果你多想一想,你可能会认为如果你在很多地方做这种事情,那么使用你的对象会开始变得特别混乱对于不太了解代码的其他人。

也许您想这样做是因为还有其他使用 Car 模型的代码想要建立连接,但并没有真正拥有完整的画面,因此它会尝试您只想在第一次成功的东西。 仅在具有完整图片的类(例如 Car 模型或服务对象)中处理此类操作要好得多。

如果您仍然真的想控制 Car 之外的这种“连接”行为,那么您可以在 Car 类中完全覆盖 attr_writer。 不过,我绝对建议在 before_save 回调上执行此操作。

def connected_at=(new_value)
  if @connected_at
    raise StandardError, 'connected_at has already been set'
  end
  @connected_at = new_value
end

无论您尝试分配值的方式如何,这都将起作用。 如果您想知道上面发生了什么,请阅读有关 ruby​​ 中的 attr_accessor 的内容。

这是我对你的问题的理解。

  • 仅当connected_at nil汽车才能更新

    class Car < ApplicationRecord before_save :updatable? def updatable? connected_at.blank? end end

重点是 before_save 时返回false

你可以:

car = Car.first
car.connected_at ||= Time.zone.now
car.save

如果将只分配connected_atnilfalse

我建议使用before_update回调并将 OP 的意图重新before_update为“如果我的属性已经有值,则丢弃更新”。

我想出了这个解决方案(它适用于大量分配,例如Car.update(car_params) ):

before_update :ignore_updates_to_connected_at

def ignore_updates_to_connected_at
  return unless connected_at.present? && connected_at_changed?

  clear_attribute_change(:connected_at)
end

<attribute_name>_changed? clear_attribute_change方法来自ActiveModel::Dirty

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM