导轨ActiveRecord关联不一致更新
-
20-09-2019 - |
题
我遇到了一些的Rails 2.3.5 ActiveRecord的行为,我不明白。看来,一个对象可以有它的关联标识不一致的方式更新。
此最好用一个例子说明:
创建与所述串的Post
模型属性'title'
以及与串的Comment
模型属性'content'
。
下面是关联:
class Post < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
end
方案1:在下面的代码创建一个Post
与相关联的Comment
,通过Post
'ing第一创建第二find
,添加第二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:再次运行上述命令,但这次插入一个额外的命令,在它的面,不应该影响的结果。额外的命令是post2.comments
发生后创建comment2
和前添加到comment2
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相关联的一个强>注释有两个。
大问题:添加新post2.comments
到Comment
任何区别,其评论用post1
关联之前为什么会运行post2
?
解决方案
这具有与活动记录缓存请求和has_many关联的处理方式的方式做。
除非关联与eagerloaded:包括查找期间选项。直到需要Rails会不填充协会发现的记录。当需要的相关的一些记忆化做是为了减少对执行的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。我的回答这个问题可能会帮助你理解为什么POST2得到尽管你不接触更新。
不隶属于 StackOverflow