如何通过关系使用has_many批量更新插入标签到rails中的记录?

问题描述 投票:0回答:1

假设我有一个帖子的经典示例,它通过标签连接表有很多标签。我如何将特定标签一次插入到满足特定条件的多个帖子中。

在伪代码中,我想我首先过滤掉任何已经具有所需标签的帖子。

tag_id = Tag.first # the desired tag
posts = Post.first(50) # example query of subset of posts
posts = posts.joins(:tags).where.not(tags: { id: tag_id }) # filter out posts that already have desired tag

现在我需要将所有选定的帖子 ID 和所需的标签 ID 插入到标签表中。

我想知道是否有一种“rails”方式可以做到这一点?

感谢您的帮助!

ruby-on-rails tags has-many-through upsert
1个回答
0
投票

鉴于:

tag = Tag.first # the desired tag. Note I changed to getting the object and calling the .id method later as your code was incorrect.
posts = Post.first(50) # example query of subset of posts
filtered_posts = posts.joins(:tags).where.not(tags: { id: tag.id }) # filter out posts that already have desired tag

一种方法:

filtered_posts.each do |p|
  p.tags << tag
end

这会循环浏览帖子并为您创建加入记录。我想说这非常 Rails-y,因为它使用内置关联,因此您甚至不需要提及标记连接表。另外,我假设您有一些验证,其中一个帖子不能用相同的标签标记两次。这可以防止这种情况发生。如果由于某种原因您需要向数千个帖子添加标签(似乎不太可能,但您永远不知道),有一些方法可以绕过为每个帖子构建对象并使用 SQL 进行更改。如果您想要运行最少的查询,您可以这样做:

t_id = tag.id 
#=> 33
post_ids = filtered_posts.ids # .ids is a built in method to get all ids without a new query
#=> [1, 23, 45, 94, ....]
insert_hash = post_ids.map {|p_id| {post_id: p_id, tag_id: t_id} }
#=> [{post_id: 1, tag_id: 33}, {post_id: 23, tag_id: 33}, {post_id: 45, tag_id: 33}, ...]
Tagging.insert_all(insert_hash)
#=> Tagging Bulk Insert (8.3ms)  INSERT INTO "taggings" ("post_id","tag_id","created_at","updated_at") VALUES (1, 33, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), (23, 33, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)...

如果您使用它,请参考

insert_all
的文档,因为它会绕过正常 Rails 流程中的验证等。 https://api.rubyonrails.org/classes/ActiveRecord/Persistence/ClassMethods.html#method-i-insert_all

© www.soinside.com 2019 - 2024. All rights reserved.