[英]rails 5 update attribute only if it's currently nil
What is the preferred way in Rails 5 with activerecord to update the attribute only if it is 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
You can simply check for #nil?你可以简单地检查#nil?
car = Car.first
car.update_attribute(:connected_at, Time.zone.now) if car.connected_at.nil?
That's not generic enough.
这还不够通用。 I want something like before_validation etc. I am just not sure which way is the preferred one.
我想要 before_validation 之类的东西。我只是不确定哪种方式是首选。
Well if you want to go for validation, it would look something like this..好吧,如果你想进行验证,它看起来像这样..
before_save :validate_connected_at
private
def validate_connected_at
connected_at = connected_at_was if connected_at_changed? && connected_at_was.present?
end
OR或者
before_save :set_connected_at
private
def set_connected_at
connected_at = Time.zone.now if connected_at.nil?
end
As you can see, more checks, more methods.如您所见,更多检查,更多方法。 I would definitely go for the first one.
我肯定会去第一个。
However, if you want to add error message, then this is the way但是,如果您想添加错误消息,那么这就是方法
errors.add(:connected_at, 'Already present!')
So "#{attr}_was" is always available on all the defined attrs in before_save method?
那么“#{attr}_was”在 before_save 方法中所有定义的属性上总是可用的?
They are available in general and not only in before_save
, eg in the console..它们通常可用,而不仅仅是在
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'
It sounds like you're saying you want to modify the behaviour of how a particular attribute works so it quietly ignores you.听起来您是在说您想修改特定属性的工作方式,以便它悄悄地忽略您。 I think the instinct behind why you want to seal this off is reasonable one but if you think about it a bit more you might consider that if you do this kind of thing in a lot of places then using your objects will start to become confusing particularly for someone else who doesn't know the code well.
我认为你为什么要封闭它的本能是合理的,但如果你多想一想,你可能会认为如果你在很多地方做这种事情,那么使用你的对象会开始变得特别混乱对于不太了解代码的其他人。
Perhaps you want to do this because there's other code using the Car model that wants to make connections but doesn't really have the full picture so it tries stuff which you only want to succeed the first time.也许您想这样做是因为还有其他使用 Car 模型的代码想要建立连接,但并没有真正拥有完整的画面,因此它会尝试您只想在第一次成功的东西。 It's much better to handle such operations solely inside a class which does have the full picture such as the Car model or a service object.
仅在具有完整图片的类(例如 Car 模型或服务对象)中处理此类操作要好得多。
If you still really want to control this "connecting" behaviour outside the Car then you can override the attr_writer completely in the Car class.如果您仍然真的想控制 Car 之外的这种“连接”行为,那么您可以在 Car 类中完全覆盖 attr_writer。 I'd definitely recommend doing this on before_save callback instead though.
不过,我绝对建议在 before_save 回调上执行此操作。
def connected_at=(new_value)
if @connected_at
raise StandardError, 'connected_at has already been set'
end
@connected_at = new_value
end
That will work whichever way you try to assign the value.无论您尝试分配值的方式如何,这都将起作用。 If you're wondering about what's going on above have a read about attr_accessor in ruby.
如果您想知道上面发生了什么,请阅读有关 ruby 中的 attr_accessor 的内容。
this is my understanding of your question.这是我对你的问题的理解。
Car can update only if connected_at
is nil
仅当
connected_at
nil
汽车才能更新
class Car < ApplicationRecord before_save :updatable? def updatable? connected_at.blank? end end
The point is return false
when before_save.重点是 before_save 时返回
false
。
You could:你可以:
car = Car.first
car.connected_at ||= Time.zone.now
car.save
That will only assign if connected_at
is nil
of false
.如果将只分配
connected_at
是nil
的false
。
I would propose to use the before_update
callback and rephrase the intention of the OP as "discard updates if my attribute already has a value".我建议使用
before_update
回调并将 OP 的意图重新before_update
为“如果我的属性已经有值,则丢弃更新”。
I came up with this solution (which works well with mass assignments such as Car.update(car_params)
):我想出了这个解决方案(它适用于大量分配,例如
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
The <attribute_name>_changed?
<attribute_name>_changed?
and clear_attribute_change
methods come from ActiveModel::Dirty .和
clear_attribute_change
方法来自ActiveModel::Dirty 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.