Вопрос

Я устанавливаю обратный вызов после_save в моем модели наблюдателя, чтобы отправить уведомление только в том случае, если модель Опубликовано атрибут был изменен с false to true. Поскольку методы, такие как измененный? Потреблять только до того, как модель сохранена, то, как я сейчас (и безуспешно), пытаясь сделать это выглядит следующим образом:

def before_save(blog)
  @og_published = blog.published?
end

def after_save(blog)
  if @og_published == false and blog.published? == true
    Notification.send(...)
  end
end

У кого-нибудь есть какие-либо предложения относительно наилучшего способа справиться с этим, предпочтительно, используя обратные вызовы моделей наблюдателя (чтобы не загрязнять мой код контроллера)?

Это было полезно?

Решение

В твоем after_update Фильтр на модели вы могу использовать _changed? Accessor (хотя бы в рельсах 3, не уверен для рельсов 2). Так, например:

class SomeModel < ActiveRecord::Base
  after_update :send_notification_after_change

  def send_notification_after_change
    Notification.send(...) if (self.published_changed? && self.published == true)
  end

end

Это просто работает.

Другие советы

Для тех, кто хочет знать изменения, только что сделанные в after_save Перезвоните:

Рельсы 5.1 и больше

model.saved_changes

Рельсы <5.1

model.previous_changes

Также см: http://api.rubyonrails.org/Classes/activeModel/dirty.html#method-deprevious_changes.

Кто-нибудь увидеть это позже, так как в настоящее время он в настоящее время (августа 2017) топы Google: стоит упомянуть, что это поведение будет изменено в Рельсы 5.2, и имеет обесценение предупреждений с рельсами 5.1, как ActiveModel :: грязно изменился немного.

Что я могу изменить?

Если вы используете attribute_changed? метод в after_*-Callbacks, вы увидите предупреждение, как:

Предупреждение о снижении: поведение attribute_changed? Внутри после обратных вызовов будут меняться в следующей версии рельсов. Новое возвращаемое значение будет отражать поведение вызывающего метода после save Вернулся (например, противоположность того, что он возвращается сейчас). Поддерживать текущее поведение, используйте saved_change_to_attribute? вместо. (называется из quey_callback на /path_to/app/models/user.rb:15)

Как упоминается, вы можете легко исправить это, заменив функцию с saved_change_to_attribute?. Отказ Так, например, name_changed? становится saved_change_to_name?.

Аналогично, если вы используете attribute_change Чтобы получить ранее после ценностей, это меняется, а также бросает следующее:

Предупреждение о снижении: поведение attribute_change Внутри после обратных вызовов будут меняться в следующей версии рельсов. Новое возвращаемое значение будет отражать поведение вызывающего метода после save Вернулся (например, противоположность того, что он возвращается сейчас). Поддерживать текущее поведение, используйте saved_change_to_attribute вместо. (называется из quey_callback на /path_to/app/models/user.rb:20)

Опять же, как упоминается, метод меняет имя saved_change_to_attribute который возвращает ["old", "new"]Отказ или использовать saved_changes, который возвращает все изменения, и их можно получить доступ как saved_changes['attribute'].

Если вы можете сделать это на before_save вместо after_save, Вы сможете использовать это:

self.changed

Он возвращает массив всех измененных столбцов в этой записи.

Вы также можете использовать:

self.changes

который возвращает хеш столбцов, изменившихся и до и после результатов в качестве массивов

«Выбранный» ответ не работал для меня. Я использую Rails 3.1 с Couchrest :: Модель (на основе активной модели). То _changed? Методы не возвращаются для измененных атрибутов в after_update крючок, только в before_update крюк. Я смог заставить его работать, используя (New?) around_update крюк:

class SomeModel < ActiveRecord::Base
  around_update :send_notification_after_change

  def send_notification_after_change
    should_send_it = self.published_changed? && self.published == true

    yield

    Notification.send(...) if should_send_it
  end

end

Вы можете добавить условие в after_update вот так:

class SomeModel < ActiveRecord::Base
  after_update :send_notification, if: :published_changed?

  ...
end

Нет необходимости добавлять условие в send_notification сам метод.

Я использую это, чтобы извлечь хеш с новыми значениями атрибута, что полезно для меня, чтобы обновить другие модели

attributes_changed = self.changes.inject(Hash.new){|hash,attr| ((hash[attr[0].to_sym] = attr[1].last) || attr[1].last == false) && hash}

То

attr[1].last == false

нужен, когда новое значение false, где назначение возвращает false и "hash" не возвращается.

Я думаю, что есть проще, я новичок в рельсы

Вы просто добавляете аксес, который определяет то, что вы меняете

class Post < AR::Base
  attr_reader :what_changed

  before_filter :what_changed?

  def what_changed?
    @what_changed = changes || []
  end

  after_filter :action_on_changes

  def action_on_changes
    @what_changed.each do |change|
      p change
    end
  end
end
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top