2017-10-25 3 views
0

다 - 대 - 다 관계로 작업 할 때 변경된 값을 기록하는 로그 파일을 유지해야합니다. before_save 및 after_save 콜백을 사용하면 기본 (has_many) 모델 자체에서 잘 작동하지만 before_save 콜백에서 관련 (belongs_to) 레코드가 이미 업데이트 된 것처럼 보입니다!'before_save'콜백이 호출되기 전에 데이터의 일부가 이미 업데이트 된 것을 보는 것이 이상하게 보입니다.관련 레코드의 이전 값을 가져 오는 방법은 무엇입니까?

또한 관련 모델에서 콜백을 사용하면 before_destroy가 실행되지 않는다는 것을 알 수 있습니다. before_save 만 호출되고 새 값이 표시됩니다. 나는 또한 : prepend => : true 옵션을 시도했지만 다른 결과를 얻지 못했습니다.

메인 (has_many) 모델의 실제 저장 전에 SQL 로깅을 켜면 Rails가 관련 레코드를 가져 와서 차이점을 확인하고 잉여 레코드를 삭제하는 것을 볼 수 있습니다. 연관된 모델의 before_destroy는 호출되지 않습니다. 그런 다음 연관된 모델의 before_save를 호출하고 새 모델을 삽입하고 (있는 경우) 트랜잭션을 커밋합니다. 이것은 주 모델의 before_save 이전에 모두 완료됩니다.

누구든지 변경되기 전에 연결된 레코드를 가져 오는 방법을 알고 있습니까? 관련 모델의 before_destroy가 호출되어 처리하도록하겠습니다.

+0

업데이트하기 전에 old_value를 원하지만 new_Value가 올바르게 표시되고 있습니까? – krishnar

+0

@krishnar : 예, 연결이 자체 테이블에 기록되므로 이전 값은 관련 테이블에서 삭제 된 것으로 보이는 레코드입니다. – GTeley

+0

음, 이전 값을 얻는 한 가지 방법을 찾았습니다. 기존 레코드에 새 값을 할당하기 직전에 컨트롤러 저장 메소드에서. 그러나 이것은 의도 된 레일스 방법이 아닌 IMHO입니다! – GTeley

답변

0

을 일부 확장 된 정보를 제공 할 수 있습니다. 그러나 author_ids에 대해 변경된 관련 값을 가져올 방법이 없습니다. Title의 before_destroy 콜백이 호출되지 않았으며 after_save가 호출되었습니다.

새 author_ids를 편집 된 레코드에 할당하기 직전에 SQL 로깅을 사용하도록 설정하여이를 확인했습니다.Rails가 기존의 값과 새 연관된 값의 차이를 확인하고, 여분의 표를 삭제하고, 여분의 표를 삽입하는 것을 볼 수 있습니다 (있는 경우)

제목의 변경 사항에 대한 로깅을 이동하여 해결했습니다. 새 값으로 이전을 비교하여 책 컨트롤러 : 내가 말했듯이

 o_authors = book.author_ids 
    n_authors = params[:book][:author_ids].collect {|c| c.to_i} 
    diff = o_authors - n_authors | n_authors - o_authors 
    if !diff.empty? 
     changed_values = [] 
     (o_authors - n_authors).each do |d| 
     changed_values.push("Removed Author: #{Author.find(d).name}") 
     end 
     (n_authors - o_authors).each do |d| 
     changed_values.push("Added Author: #{Author.find(d).name}") 
     end 
     BookLog.create(:book_id => book.id, :changed_values => changed_values) 
    end 
    book.author_ids = params[:book][:author_ids] 
    book.save! 

, 그것은 작동하지만 이럴가 레일을 일을하는 방법을 반영하지 않습니다. 다른 book 속성과 같은 방법으로 이전 author_ids를 가져올 것으로 예상됩니다.

0

사용 before_update 당신은 귀하의 질문이 좀 불분명 _was

before_update :record_values 


def record_values 
    p "oldvalue: #{self.field_was} Newvalue: #{self.field}" 
end 
+0

내가 말했듯이, 메인 모델에 대한 오래된 값을 얻는 것은 문제가되지 않습니다. 연관된 (has_many) 레코드를 얻는 것이 문제입니다. 모델 컨트롤러의 관련 필드에 새 값을 할당하면 save를 호출하기 전에 Rails가 before_save 콜백에서 해당 테이블을 가져 오기 전에 관련 테이블을 업데이트합니다. – GTeley

+0

* has_many * 관계에는 여전히 상대방에 * belongs_to *가 있습니다. * before_save *를 설정하면 어떻게됩니까? –

0

사용 된 값에 액세스하지만, 제가 당신이하려고 생각의 예를 제공하도록 할 수 있습니다.

아래 코드는 나를 위해 잘 작동 : 상호 작용하는 경우는 다음과 같은 출력 결과

class Person < ApplicationRecord 
    has_many :addresses 

    validates_presence_of :name 

    before_save { puts "before_save of person - changes: #{changes}" } 
    before_destroy { puts "before_destroy of person with id: #{id}" } 
end 

class Address < ApplicationRecord 
    belongs_to :person, required: true 

    validates_presence_of :name 

    before_save { puts "before_save of address - changes: #{changes}" } 
    before_destroy { puts "before_destroy of address with id: #{id}" } 
end 

:

person = Person.create(name: 'Johan Wentholt') 
# before_save of person - changes: {"name" =>[nil, "Johan Wentholt"]} 
#=> #<Person id: 2, name: "Johan Wentholt", created_at: "2017-10-25 15:04:27", updated_at: "2017-10-25 15:04:27"> 

person.addresses.create(name: 'Address #1') 
# before_save of address - changes: {"person_id"=>[nil, 2], "name" =>[nil, "Address #1"]} 
#=> #<Address id: 7, person_id: 2, name: "Address #1", created_at: "2017-10-25 15:06:38", updated_at: "2017-10-25 15:06:38"> 

person.addresses.last.update(name: 'Address without typo') 
# before_save of address - changes: {"name"=>["Address #1", "Address without typo"]} 
#=> true 

person.update(name: 'Kaasboer') 
# before_save of person - changes: {"name"=>["Johan Wentholt", "Kaasboer"]} 
#=> true 

person.addresses.last.destroy 
# before_destroy of address with id: 7 
#=> #<Address id: 7, person_id: 2, name: "Address without typo", created_at: "2017-10-25 15:06:38", updated_at: "2017-10-25 15:08:51"> 

person.destroy 
# before_destroy of person with id: 2 
#=> #<Person id: 2, name: "Kaasboer", created_at: "2017-10-25 15:04:27", updated_at: "2017-10-25 15:10:46"> 

을이 모든 변경 사항을 기록합니다 볼 수 있듯이. 제가 말했듯이, 질문은 약간 불분명하지만, 이것이 당신을 더 멀리하는 데 도움이되기를 바랍니다.

일부 Rails 메서드는 콜백을 트리거하지 않습니다. 예 : , update_all, update_column 등을 삭제하십시오. 변경 사항에 대한 자세한 내용은

이 한 번 봐 걸릴 :

이 책 레코드에
class Book < ActiveRecord::Base 
    unloadable 
    has_many :titles, dependent: :destroy 
    has_many :authors, :through => :titles 
    accepts_nested_attributes_for :authors 

    before_save :pre_save 
    after_save :post_save 
    before_destroy :pre_delete 

    def pre_save 
    @nr = self.new_record? 
    end 

    def pre_save 
    changed_values = [] 
    if @nr 
     changed_values.push "New record created" 
    else 
     self.changes.each do |field, cvs| 
     changes.push("#{field} : #{cvs[0]} => #{cvs[1]}") 
     end 
    end 
    if changes.length > 0 
     BookLog.create(:book_id => self.id, :changed_values => changes.join(', ')) 
    end 
    end 

    def pre_delete 
    BookLog.create(:book_id => self.id, :changed_values => "Deleted: #{self.name}") 
    end 
end 

class Title < ActiveRecord::Base 
    unloadable 
    belongs_to :book 
    belongs_to :author 
end 

class Author < ActiveRecord::Base 
    unloadable 
    has_many :titles, dependent: :destroy 
    has_many :books, :through => :titles 
    accepts_nested_attributes_for :books 
end 

class BooksController < ApplicationController 

    def edit 
    book = Book.find(params[:book][:id]) 
    book.name = ..... 
    ===> Here the old values are still available <==== 
    book.author_ids = params[:book][:author_ids] 
    ===> Now the new values are written to the database! <==== 
    book.save! 
    end 
end 

변경은 (는) 도심에 기록됩니다 선명도를 위해서 ActiveModel::Dirty

+0

답장을 보내 주셔서 감사합니다. 어쩌면 충분히 명확하지 않을 수도 있습니다. 내 문제는 관계 테이블에 기록 된 다 대 다 관계입니다. 변경 사항 감지 has_many 모델에서 잘 작동하지만 belongs_to 모델 (has_many, : through)에 적용되지 않음 새 값이 related_to에 할당되기 전에 변경 사항을 기록하여 주 모델 컨트롤러에서이를 해결했습니다 ids. – GTeley