代码之家  ›  专栏  ›  技术社区  ›  rlandster

Rails ActiveRecord关联更新不一致

  •  1
  • rlandster  · 技术社区  · 16 年前

    我遇到了一些我不理解的Rails 2.3.5活动记录行为。对象的关联ID可能以不一致的方式更新。

    这最好用一个例子来解释:

    创建一个 Post 具有字符串属性的模型 'title' 和A Comment 具有字符串属性的模型 'content' .

    以下是关联:

    class Post < ActiveRecord::Base
      has_many :comments
    end
    
    class Comment < ActiveRecord::Base
      belongs_to :post
    end
    

    场景1:在下面的代码中,我创建了一个 与关联的 评论 ,创建第二个 通过 find '在第一个,添加第二个 评论 到第一 发现第二个 有第二 评论 与它关联,但没有显式赋值。

    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:再次运行上述命令,但这次插入一个额外的命令,从表面上看,该命令不应影响结果。额外的命令是 post2.comments 发生了什么 之后 创建 comment2 之前 添加 评论2 post1 .

    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]
    

    注意只有 与关联的注释 post2 在这个场景中,而在场景1中有两个。

    大问题:为什么要跑步 帖子2评论 在添加新的 评论 POST 1 对注释所关联的内容进行任何更改 POST 2 ?

    1 回复  |  直到 16 年前
        1
  •  2
  •   Community Mohan Dere    9 年前

    这与活动记录缓存请求的方式以及处理多个关联的方式有关。

    除非该关联在查找过程中被急切地加载了:include选项。在需要之前,Rails不会填充找到的记录的关联。当需要关联时 memoization 这样做是为了减少执行的SQL查询的数量。

    单步执行问题中的代码:

    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)

    P.S.我的回答 this question 也许可以帮助你理解为什么post2会被更新,尽管你没有接触它。