2009-04-17 3 views
2

현재의 레일즈 앱에서 나는 데이터베이스에서 많은 데이터를 메모리로 가져 와서 오랫동안 실행되는 백그라운드 작업을 시작할 수 있습니다. 5 초.메모리에서 eager-loaded associations 업데이트하기

이것은 모두 훌륭하게 작동하지만 가능하면 없애고 싶은 멋진 코드가 있습니다.

예를 들어 필자는 사용자 모델이 있고 사용자 모델이 연락처 형식으로 다른 사용자 모델에 연결될 수있는 상황을 가지며이 사용자 모델은 다시 첫 번째 사용자 모델로 다시 연결할 수 있습니다.

class User < ActiveRecord::Base 
    has_many :contact_records, :foreign_key => :owner_id 
    has_many :contacts, :through => :contact_records, :class_name => "User" 
end 

class ContactRecord < ActiveRecord::Base 
    belongs_to :owner, :class_name => "User" 
    belongs_to :user 
end 

그래서 지금은

user_a_contacts = user_a.contact_records 
=> [user_b, user_c] 

를 입력하고 사용자 A의 모든 연락처를 얻을 수 있습니다 - (그의 초기 도움 밀란 Novota 덕분에) 이것은 다음과 같이 모델링된다. 이제 나는 사용자 A의를 통해 사용자 B의 연락처를 얻을하고 싶은 말은하자 (왜 것이라고 생각할 수 있지만 그것은 단지 예입니다!)

user_b_contacts = user_a_contacts.first.contact_records 
=> [user_a, user_c] 

을 지금은, 뒤얽힌, 원형 교차로에서 (사용자 A의 이름을 결코 얻을 수 없다 실용적인 방식으로 사용하십시오)

user_a_name = user_b_contacts.first.name 
=> "Jamie" 

지금까지 그렇게 좋았습니다. 내가

를 얻을 데이터베이스에서 이전처럼 다시 사용자 A의 이름에 접근 나는 열망로드 한 경우, 그러나

user_a_name = user_b_contacts.first.name 
=> "Sandy" 

을 얻을 메모리에이 값을 유지하는 경우 지금은 사용자 A의 이름

user_a.name = "Sandy" 
=> "Sandy" 

변경

user_a_name = user_b_contacts.first.name 
=> "Jamie" 

그러나 다음을 수행하는 것은 나에게 정답을 제공

user_a.name 
=> "Sandy" 

분명히 eager-loading은 원래 사용자와 ContactRecord 객체에서 열심히로드 된 다른 User 객체를 생성합니다.

그래서 (드디어!) 내 질문은이 : -

순간

, 나는 @users는 사용자 개체의 열망로드 목록입니다 (

@users.each.detect{|user| user == user_b_contacts.first} 

를 사용하여이 문제를 bodged있다). 대신 열심히로드 된 사용자 개체를 업데이트 할 수있는 방법이 있습니까?

주의 사항 : -

A) 나는 다음과 같은

User.find(:all, :include => [ {:contact_records => :contacts] } ]) 

B를 사용 열망 로딩입니다) 분명히 이것은 내가 함께 일하고 실제 코드가 아니라 더가 있었을 것이다 설명과 박람회는 코드를 보여주기에 충분하다고 생각합니다. 실제로 사용하고있는 실제 예가 제대로 작동하려면이 구조가 필요하다는 것을 믿어주세요. 기괴한 것처럼 보일 수도 있습니다.;)

c) 예제를 재구성 할 때 오타 및 오류가 발생할 수 있지만 무시하십시오. 필자가 알아야 할 것은 데이터베이스를 손상시키지 않으면 서 열정적 인 사용자를 다시로드 할 수 있는지 여부입니다.

미리 감사드립니다.

업데이트 : 모델 데이터는 프로세스가 끝날 때까지 데이터베이스에 저장되지 않으므로 데이터베이스의 데이터가 변경되지 않으므로 다시로드 할 수 없습니다.

답변

4

확인. 귀하의 질문을 새로운 질문으로 응축하고 그 질문에 대답하겠습니다. 내가 오해하고 이것이 당신이 묻고있는 것이 아니라면 용서하십시오.

질문

user 경우이 데이터베이스에 변경되었을 때 나는 contacts 연결을 새로 고침 어떻게, 내가 앞서 User.first(:include => :contacts)와 시간의 관계 contacts를로드 한 액티브 모델이다?

당신은 내가 알고있는 두 가지 방법으로 연결 캐시를 무효화 할 수

대답. 먼저 다음을 할 수 있습니다.

user.reload 

전체 사용자 모델을 처음부터 다시로드합니다. 이 작업을 수행하는 약간 덜 과감한 방법은 user 모두를 다시로드하지 않습니다

user.clear_association_cache 

을하는 것입니다,하지만 캐시 연결을 취소합니다.

다음 번에 user.contacts을 할 때 데이터베이스에서 새로로드합니다.

0

답장을 보내 주신 Daniel에게 많은 감사를드립니다. 당신이 옳은 질문을 얻지 못했지만, 나는 중요한 포인트를 놓쳤다는 것을 깨달았습니다! 저장하지 않으므로 데이터베이스 레코드가 업데이트되지 않습니다! 언제든지.

내가하고있는 것의 요지는 백그라운드 프로세스의 속도를 높이기 위해 모델 데이터를 인스턴스 변수로 가져 오는 것입니다. 따라서 프로세스가 끝날 때까지 처음으로로드 된 데이터는 다시 데이터베이스에 저장되지 않습니다.

내가 원했던 것은 한 열의 값이 이미로드 된 다른 모델과 관련된 eager-loading을 지정할 수있는 방법이었습니다. 예를 들어

,

User.find(:all, :include => [ {:contact_records => (:contacts as User)] } ]) 

또는 유사한.

필자가 알고있는 한, 레일스에는 그런 구문이 없다는 것이지만, 나는 틀렸다고 기대하고있다. :)

희망이 조금 더 명확하게하고 답장을 보내 주셔서 감사합니다.

관련 문제