after_save에서 레코드가 방금 생성되었거나 업데이트되었는지 확인하는 방법


96

#new_record? 함수는 레코드가 저장되었는지 여부를 결정합니다. 그러나 그것은 항상 거짓입니다 after_save. 레코드가 새로 생성 된 레코드인지 아니면 업데이트에서 이전 레코드인지 확인하는 방법이 있습니까?

before_create모델에 플래그를 설정하거나 db에 대한 다른 쿼리를 요구하는 것과 같은 다른 콜백을 사용하지 않기를 바랍니다 .

조언을 주시면 감사하겠습니다.

편집 : 필요는 그것을 결정 없습니다 after_save후크, 내 특정 유스 케이스를 위해, 더이 updated_atupdated_on타임 스탬프를


1
흠 아마도 before_save에 매개 변수를 전달할 수 있습니까? 소리내어 생각하기
Trip

답변:


169

나는 이것을 after_save콜백 에 사용하려고했습니다 .

더 간단한 해결책은 (에서 id_changed?변경되지 않기 때문에 update) 또는 created_at_changed?타임 스탬프 열이있는 경우 에도 사용하는 것입니다.

업데이트 : @mitsy가 지적했듯이 콜백 외부 에서이 확인이 필요한 경우 id_previously_changed?. 문서를 참조하십시오 .



6
after_update 및 after_create로 차별화하는 것이 가장 좋습니다. 콜백은 생성인지 업데이트인지 나타내는 인수를 사용하는 공통 메서드를 공유 할 수 있습니다.
matthuhiggins 2010 년

2
이것은 변경되었을 수 있습니다. 적어도 Rails 4에서는 after_save 콜백이 after_create 또는 after_update 콜백 이후에 실행됩니다 ( guides.rubyonrails.org/active_record_callbacks.html 참조 ).
Mark

3
이러한 필드를 모두 확인하는 것은 after_save.
fatuhoku

3
id_changed?레코드가 저장된 후 거짓이됩니다 (적어도 후크 외부). 이 경우 다음을 사용할 수 있습니다id_previously_changed?
mltsy

31

내가 아는 레일 마술은 여기에서 직접 수행해야합니다. 가상 속성을 사용하여이를 정리할 수 있습니다.

모델 클래스에서 :

def before_save
  @was_a_new_record = new_record?
  return true
end

def after_save
  if @was_a_new_record
    ...
  end
end

26

그러나 사람들을위한 또 다른 옵션을 할 수는updated_at타임 스탬프를 :

if created_at == updated_at
  # it's a newly created record
end

나쁜 생각은 아니지만 일부 상황에서는 역효과를 낼 수있는 것 같습니다 (반드시 방탄은 아님).
Ash Blue

마이그레이션이 실행되는시기에 따라 created_at 및 updated_at 레코드가 꺼질 수 있습니다. 또한 처음에 저장 한 직후 누군가가 레코드를 업데이트 할 수있는 기회가 주어 지므로 시간이 동기화되지 않을 수 있습니다. 그것은 나쁜 생각이 아니라 더 많은 방탄 구현이 추가 될 수있는 것처럼 느껴집니다.
Ash Blue

또한 레코드가 처음 생성 된 후 오랫동안 동일 할 수 있습니다. 레코드가 몇 달 동안 업데이트되지 않으면 방금 만들어진 것처럼 보일 것 입니다 .
bschaeffer

1
죄송합니다 @bschaeffer, 내 질문이었다 "그것은 가능하다 created_at같음 updated_atafter_save가 처음 만들어 질 때 이외의 시간에 콜백?"
colllin

1
@colllin : 기록을 생성 할 때 created_at와 것은 updated_at동등한 것 after_save콜백. 다른 모든 상황에서는 after_save콜백 에서 동일하지 않습니다 .
bschaeffer

22

after_create레코드 가 저장된 후 새 레코드 인 경우에만 호출 되는 콜백이 있습니다. after_update변경 및 저장 한 기존 레코드 인 경우 사용할 콜백 도 있습니다 . after_save중 후 콜백은, 두 경우 모두 호출 after_create하거나하는 것은 after_update이라고합니다.

after_create새 레코드를 저장 한 후 한 번 발생해야하는 경우에 사용하십시오 .

자세한 정보 : http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html


1
대답 해 주셔서 감사합니다. 이것은 저에게 많은 도움이되었습니다. Cheers man, +10 :)
Adam McArthur

1
이것은 사실이 아닐 수도 있습니다. 생성에 연결이있는 경우 연결이 생성되기 전에 after_create가 호출되므로 EVERYTHING이 생성되었는지 확인해야하는 경우 after_save를 사용해야합니다.
Niels Kristian

18

개체가 이미 저장되었으므로 이전 변경 사항을 확인해야합니다. ID는 생성 후에 만 ​​변경해야합니다.

# true if this is a new record
@object.previous_changes[:id].any?

인스턴스 변수도 @new_record_before_save있습니다. 다음을 수행하여 액세스 할 수 있습니다.

# true if this is a new record
@object.instance_variable_get(:@new_record_before_save)

둘 다 꽤 못 생겼지 만 객체가 새로 생성되었는지 여부를 알 수 있습니다. 도움이 되었기를 바랍니다.


나는 현재 after_saveRails 4를 사용 하는 콜백 에서 byebug에 있으며 이들 중 어느 것도이 새로운 레코드를 식별하기 위해 노력하지 않습니다.
MCB

나는 말하고 싶지만 @object.previous_changes[:id].any?매우 간단하고 우아한입니다. 레코드가 업데이트 된 후에 작동합니다 (에서 전화하지 않음 after_save).
thekingoftruth jul.

1
@object.id_previously_changed?좀 덜 못 생겼습니다.
aNoble

after_saveRails 4 에서 @MCB changes[:id]대신 previous_changes[:id]. 그러나 이것은 (토론 참조 Rails5.1에 변화 github.com/rails/rails/pull/25337를 )
gmcnaughton

previous_changes.key?(:id)더 나은 이해를 위해.
Sebastian Palma

3

Rails 5.1+ 방식 :

user = User.new
user.save!
user.saved_change_to_attribute?(:id) # => true

1

Rails 4 (4.2.11.1에서 확인 됨)의 경우 changesprevious_changes메서드의 결과는 {}내부 객체 생성시 빈 해시 입니다 after_save. 따라서 attribute_changed?같은 방법 id_changed?은 예상대로 작동하지 않습니다.

그러나이 지식을 활용할 수 있으며 changes업데이트 시 적어도 하나의 속성이 있어야한다는 것을 알고 changes비어 있는지 확인하십시오 . 비어 있음을 확인한 후에는 객체 생성 중에 있어야합니다.

after_save do
  if changes.empty?
    # code appropriate for object creation goes here ...
  end
end

0

나는 :id정상으로 바뀌면 안된다는 것을 알고 있지만 구체적으로 말하고 싶지만

(byebug) id_change.first.nil?
true

매우 이상하고 예기치 않은 버그를 찾는 대신 구체적으로 지정하는 것이 항상 저렴합니다.

true신뢰할 수없는 주장에서 플래그를 기대하는 경우에도 마찬가지입니다.

def foo?(flag)
  flag == true
end

이것은 이상한 버그에 앉지 않기 위해 많은 시간을 절약합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.