1

일부 레일스 2.3.5 ActiveRecord 동작으로 실행되고 있습니다. 이해가되지 않습니다. 객체가 일관성없는 방식으로 업데이트 된 연관 ID를 가질 수 있습니다. 레일스 ActiveRecord 연관성이 일관성없이 업데이트되었습니다.

가장 예를 들어 설명한다 :

문자열과 Post 모델을 작성 'title' 속성과 문자열을 가진 Comment 모델은 'content' 때문이다.

class Post < ActiveRecord::Base 
    has_many :comments 
end 

class Comment < ActiveRecord::Base 
    belongs_to :post 
end 

시나리오 # 1 : 여기

는 연관있는 다음 코드에서 나는 관련 Comment 하나 Post는, 첫 번째를 보내고 ' find에 의해 두 번째 Post을 만들에 두 번째 Comment를 추가 작성 먼저 Post을 찾아 두 번째 Post에 명시적인 할당없이 두 번째 Comment이 연결되어 있음을 확인하십시오.

post1 = Post.new 
post1 = Post.new(:title => 'Post 1') 
comment1 = Comment.new(:content => 'content 1') 
post1.comments << comment1 
post1.save 
# Create a second Post object by find'ing the first 
post2 = Post.find_by_title('Post 1') 
# Add a new Comment to the first Post object 
comment2 = Comment.new(:content => 'content 2') 
post1.comments << comment2 
# Note that both Comments are associated with both Post objects even 
# though I never explicitly associated it with post2. 
post1.comment_ids # => [12, 13] 
post2.comment_ids # => [12, 13] 

시나리오 # 2 : 다시 위의 명령을 실행하지만, 이번에는 그것의 얼굴에, 결과에 영향을 미치지 않습니다, 하나 개의 추가 명령을 삽입합니다. 추가 명령은 이후에이 발생하고 comment2 전에 post1이 추가되기 전에 발생하는 post2.comments입니다

두 가지가 있었다 시나리오 1에서 반면이 시나리오에서 post2과 관련된 유일한 하나 의견이 있음을
post1 = Post.new 
post1 = Post.new(:title => 'Post 1A') 
comment1 = Comment.new(:content => 'content 1A') 
post1.comments << comment1 
post1.save 
# Create a second Post object by find'ing the first 
post2 = Post.find_by_title('Post 1A') 
# Add a new Comment to the first Post object 
comment2 = Comment.new(:content => 'content 2A') 
post2.comments # !! THIS IS THE EXTRA COMMAND !! 
post1.comments << comment2 
# Note that both Comments are associated with both Post objects even 
# though I never explicitly associated it with post2. 
post1.comment_ids # => [14, 15] 
post2.comment_ids # => [14] 

참고.

큰 질문 : Commentpost1에 새로 추가하기 전에 post2.comments을 실행하면 왜 의견이 post2과 관련이 있습니까?

답변

2

이것은 Active Record가 요청을 캐싱하는 방식과 has_many 연관이 처리되는 방식과 관련이 있습니다.

찾기 작업 중에 : include 옵션을 사용하여 연관을 eagerloaded하지 않는 한. Rails는 필요할 때까지 발견 된 레코드에 대한 연관을 채우지 않습니다. 연결이 필요하면 실행 된 SQL 쿼리의 수를 줄이기 위해 memoization이 수행됩니다.

post1 = Post.new(:title => 'Post 1') 
comment1 = Comment.new(:content => 'content 1') 
post1.comments << comment1 # updates post1's internal comments cache 
post1.save 

# Create a second Post object by find'ing the first 
post2 = Post.find_by_title('Post 1') 

# Add a new Comment to the first Post object 
comment2 = Comment.new(:content => 'content 2') 
post1.comments << comment2 # updates post1's internal comments cache 

# Note that both Comments are associated with both Post objects even 
# though I never explicitly associated it with post2. 
post1.comment_ids # => [12, 13] 

# this is the first time post2.comments are loaded. 
# SELECT comments.* FROM comments JOIN comments.post_id = posts.id WHERE posts.id = #{post2.id} 
post2.comment_ids # => [12, 13] 

시나리오 2 :

post1 = Post.new(:title => 'Post 1A') 
comment1 = Comment.new(:content => 'content 1A') 
post1.comments << comment1 
post1.save 

# Create a second Post object by find'ing the first 
post2 = Post.find_by_title('Post 1A') 

# Add a new Comment to the first Post object 
comment2 = Comment.new(:content => 'content 2A') 

# first time post2.comments are loaded. 
# SELECT comments.* FROM comments JOIN comments.post_id = posts.id WHERE 
# posts.id = post2.comments #=> Returns one comment (id = 14) 
# cached internally. 

post1.comments << comment2 
# Note that both Comments are associated with both Post objects even 
# though I never explicitly associated it with post2. 
post1.comment_ids # => [14, 15] 

# post2.comment has already been cached, so the SQL query is not executed again. 

post2.comment_ids # => [14] 

N.B. 질문에 코드를 단계별로

post2.comment_ids은 내부적으로는 post2.comments.map(&:id)

으로 정의됩니다. this question에 대한 내 대답은 내게 만지지 않고도 왜 post2가 업데이트되는지 이해하는 데 도움이됩니다.

+0

답변 해 주셔서 감사합니다. 그러나이 행동이 잘못된 것처럼 보이지 않습니까? 캐싱은 결과의 불일치를 초래하지 않고 성능을 향상시켜야합니다. – rlandster

+0

더 많은 동시성 문제가 있습니다. Rails는 외부 소스가 모델 인스턴스와 관련된 사항을 변경하지 않을 것으로 기대합니다.이 경우 외부 소스는 특정 인스턴스 이외의 곳에서 발생하는 모든 동작을 의미합니다. 이것이 틀렸다는 것을 강력히 믿는다면, 버그 리포트를 제출하십시오. – EmFi

관련 문제