【问题标题】:Detecting if value of attribute changed during last update doesnt work with Active Model Dirty检测上次更新期间属性值是否更改不适用于 Active Model Dirty
【发布时间】:2016-08-30 18:24:46
【问题描述】:

仅当当前更新修改了我的列状态值时,我才尝试在我的 rails 应用程序中发送通知电子邮件。我尝试使用一些帖子中建议的 Active Model Dirty 和 status_changed? 方法。不幸的是,我的电子邮件从未发送,因为@partnership.status_changed?即使在上次更新期间确实更改了 status 的值,也会不断返回 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

我做错了什么?

【问题讨论】:

    标签: ruby-on-rails controller attributes activemodel


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

      对于您的用例,您要使用的是 previous_changes 方法,该方法返回一个散列,其中键是更改的属性,值是 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
      

      我的伪代码可能是错误的,但原理是有效的。我以前被这个“陷阱”咬过,我希望 Rails 核心团队能改变它。

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

      【讨论】:

        【解决方案3】:

        您可以尝试这种方法来检查活动记录的更改属性。

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

        如果它返回 true,那么我们的状态属性在此记录中已更改。

        【讨论】:

          【解决方案4】:

          按照docs 使用@partnership.saved_change_to_status?@partnership.saved_change_to_attribute(:status)

          【讨论】:

            【解决方案5】:

            这是您可以进入模型的一种最适合您的情况的单行方法:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2022-11-30
              • 2019-08-18
              • 1970-01-01
              • 2021-04-17
              • 2020-01-02
              • 1970-01-01
              • 2020-10-04
              相关资源
              最近更新 更多