【问题标题】:Deleting records from HABTM association从 HABTM 关联中删除记录
【发布时间】:2013-06-18 16:26:33
【问题描述】:

我正在尝试做一些相当简单的事情。我有两个模型,用户和组。为简单起见,假设它们看起来像这样:

class User < ActiveRecord::Base
  has_and_belongs_to_many :groups
end

class Group < ActiveRecord::Base
  has_and_belongs_to_many :users
end

现在,由于某种原因,我有一个用户两次拥有相同的组。在 Rails 控制台中:

user = User.find(1000)

=> #<User id: 1000, first_name: "John", last_name: "Doe", active: true, created_at:
"2013-01-02 16:52:36", updated_at: "2013-06-17 16:21:09">

groups = user.groups

=> [#<Group id: 1, name: "student", is_active: true, created_at: "2012-12-24 15:08:59",
updated_at: "2012-12-24 15:08:59">, #<Group id: 1, name: "student", is_active: true,
created_at: "2012-12-24 15:08:59", updated_at: "2012-12-24 15:08:59">]

user.groups = groups.uniq

=> [#<Group id: 1, name: "student", is_active: true, created_at: "2012-12-24 15:08:59",
updated_at: "2012-12-24 15:08:59">]

user.save

=> true

还有一些我已经静音的 SQL 输出。我认为一切都应该准备就绪,但事实并非如此。这些组没有更新,并且该用户仍然拥有两者。我可以进入连接表并手动删除重复项,但这似乎很笨拙、粗暴且不必要。我在这里做错了什么?

我正在运行 Rails 3.2.11 和 Ruby 1.9.3p392

附加说明:我尝试了很多不同的方法,包括使用 user.update_attributes,以及使用 group_ids 而不是组本身,但无济于事。

【问题讨论】:

  • 这是发布时的拼写错误,在控制台中变量名称保持一致。
  • 我想先检查一下简单的东西。 ;-)
  • 将 'uniq: true' 添加到关系中将帮助您“获取” uniq 记录,但它不会停止创建重复项。见stackoverflow.com/questions/1129781/…
  • 很高兴知道,谢谢。但是有什么解释为什么这不起作用,以及我将如何使它起作用?

标签: ruby-on-rails ruby


【解决方案1】:

这不起作用的原因是 ActiveRecord 没有处理 habtm 关联中重复项的无效状态(或任何CollectionAssociation)。任何未包含在新分配的数组中的ids 都将被删除 - 但在这种情况下没有任何内容。相关代码:

# From lib/active_record/associations/collection_association.rb

def replace_records(new_target, original_target)
  delete(target - new_target)
  unless concat(new_target - target)
    @target = original_target
    raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
                          "new records could not be saved."
  end
  target
end

传递的“目标”是分配记录的数组。请注意,在您的情况下,对delete(target - new_target) 的调用等效于delete(user.groups - user.groups.uniq),这会导致传递一个空数组(因为比较基于每条记录的id 属性)。

相反,您需要清除关联,然后再次重新分配单个组:

group = user.groups.first
user.groups.clear
user.groups << group

【讨论】:

    【解决方案2】:

    这可能是一种清理这些重复项的方法(它可以处理任意数量的重复关联组):

    user = User.find(1000)
    
    user.groups << user.groups.group_by(&:id).values.find_all {|v| v.size > 1}.each {|duplicates| duplicates.uniq_by! {|obj| obj.id}}.flatten.each {|duplicate| user.groups.delete(duplicate)}
    

    【讨论】:

      猜你喜欢
      • 2011-04-29
      • 2023-03-08
      • 1970-01-01
      • 2014-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-17
      • 2021-11-14
      相关资源
      最近更新 更多