[ruby-on-rails] Rails after_save 콜백에서 변경된 속성을 결정 하시겠습니까?

모델의 게시 된 속성이 false에서 true로 변경된 경우에만 알림을 보내도록 모델 관찰자에서 after_save 콜백을 설정하고 있습니다. 같은 방법이 바뀌 었습니까? 모델이 저장되기 전에 만 유용합니다. 현재 (그리고 실패한) 방법은 다음과 같습니다.

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

누구든지이를 처리하는 가장 좋은 방법에 대한 제안이 있습니까? 모델 관찰자 콜백을 사용하는 것이 좋습니다 (컨트롤러 코드를 오염시키지 않도록)?



답변

레일스 5.1+

사용 saved_change_to_published?:

class SomeModel < ActiveRecord::Base
  after_update :send_notification_after_change

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

end

또는 원하는 경우 saved_change_to_attribute?(:published).

레일 3–5.1

경고

이 방법은 Rails 5.1을 통해 작동하지만 5.1에서는 더 이상 사용되지 않으며 5.2에서는 주요 변경 사항이 있습니다. 이 풀 요청 의 변경 사항에 대해 읽을 수 있습니다 .

after_update모델 의 필터에서 접근자를 사용할 있습니다 _changed?. 예를 들어 :

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-i-previous_changes


답변

그것은 언급 할만큼 가치가이 동작이 변경 될 것입니다 : 현재 그것으로, 나중에 (8 월 2017)이 보는 사람에게 구글 꼭대기 레일 5.2 과 같이 레일 5.1로 중단 경고를 가지고 ActiveModel :: 더러운 조금 변경 .

무엇을 바꾸나요?

-callbacks attribute_changed?에서 메소드를 사용 하는 경우 다음 after_*과 같은 경고가 표시됩니다.

감가 상각 경고 : attribute_changed?다음 버전의 레일에서는 콜백 내부 동작 이 변경됩니다. 새로운 리턴 값은 save리턴 된 후 메소드를 호출하는 동작을 반영합니다 (예 : 지금 리턴하는 것과 반대). 현재 동작을 유지하려면 saved_change_to_attribute?대신 사용하십시오. (/PATH_TO/app/models/user.rb:15의 some_callback에서 호출)

언급했듯이 함수를로 바꾸면 쉽게 해결할 수 있습니다 saved_change_to_attribute?. 예를 들어, name_changed?됩니다 saved_change_to_name?.

마찬가지로,를 사용하여 attribute_change전후 값을 가져 오는 경우에도 변경되며 다음과 같은 결과가 발생합니다.

감가 상각 경고 : attribute_change다음 버전의 레일에서는 콜백 내부 동작 이 변경됩니다. 새로운 리턴 값은 save리턴 된 후 메소드를 호출하는 동작을 반영합니다 (예 : 지금 리턴하는 것과 반대). 현재 동작을 유지하려면 saved_change_to_attribute대신 사용하십시오. (/PATH_TO/app/models/user.rb:20의 some_callback에서 호출)

다시 말하지만, 메소드는 name을 saved_change_to_attribute로 변경 합니다 ["old", "new"]. 또는을 사용 saved_changes하면 모든 변경 사항이 반환되며으로 액세스 할 수 있습니다 saved_changes['attribute'].


답변

before_save대신 에이 작업을 수행 할 수있는 경우 다음 after_save을 사용할 수 있습니다.

self.changed

이 레코드에서 변경된 모든 열의 배열을 반환합니다.

당신은 또한 사용할 수 있습니다 :

self.changes

결과는 전후로 변경된 열의 해시를 배열로 반환합니다.


답변

“선택된”답변이 효과가 없었습니다. CouchRest :: Model (액티브 모델 기반)과 함께 레일 3.1을 사용하고 있습니다. _changed?방법은 변경 속성에 대해 true를 반환하지 않습니다 after_update만에, 훅 before_update훅. (새로운?) 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메소드 자체 내에 조건을 추가 할 필요가 없습니다 .


답변

변경 내용을 정의하는 접근자를 추가하기 만하면됩니다.

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