检测上次更新期间属性值是否更改不适用于 Active Model Dirty

Detecting if value of attribute changed during last update doesnt work with Active Model Dirty

我试图在我的 rails 应用程序中发送通知电子邮件,仅当我的列状态值被当前更新修改时。我尝试按照某些 post 和 status_changed? 方法中的建议使用 Active Model Dirty。不幸的是,我的电子邮件从未发送过,因为@partnership.status_changed?持续 returns false 即使状态的值在上次更新期间确实发生了变化。这是我的控制器代码:

  def update
    authorize @partnership
    if @partnership.update(partnership_params)
      send_notification_email
      render json: {success: "partnership successfully updated"}, status: 200
    else
      render_error(nil, @partnership)
    end
  end

  private

  def send_notification_email
    PartnershipMailer.partnership_status_change(@partnership).deliver_now if @partnership.status_changed?
  end

我还在我的模型中加入了 Active Model Dirty :

class Partnership < ActiveRecord::Base
  include ActiveModel::Dirty

我做错了什么?

.update 也会在更新数据后保存模型,因此会重置脏值。尝试使用 .assign_attributes。它只会分配属性,然后您可以检查更改,最后记得保存模型。

您可以尝试使用此方法查看活动记录的更改属性。

@partnership.changed.include?("status")

如果 returns 为真,则我们的状态属性已在此记录中更改。

这是您可以在最适合您的情况的模型中使用的一种单行方法:

after_commit :send_notification_email, if: Proc.new { |model| model.previous_changes[:status]}

正如@Thounder 指出的那样,每当您保存记录时,ActiveModel::Dirty 方法 <attribute>_changed? 都会被重置。因此,它只跟踪保存之间的变化。

对于您的用例,您要使用的是 previous_changes 方法,该方法 returns 一个散列,其键是已更改的属性,值是 2 个值的数组:旧和新的。

person = Person.new(name: "Bob")
person.name_changed? # => true
person.save
person.name_changed? # => false (reset when save called)
person.previous_changes # => { name: [nil, "Bob"] }
person.previous_changes[:name] # => returns a "truthy" statement if :name attribute changed

我的伪代码可能有误,但原理是可行的。之前就被这个"gotcha"坑过,希望Rails核心团队改一下

我理解他们的推理,但对我来说在保存后跟踪 <attribute>_changed? 更有意义,因为这对我来说似乎是常见的用例。

根据 docs 使用 @partnership.saved_change_to_status?@partnership.saved_change_to_attribute(:status)