【问题标题】:Active record update_attribute executes a DELETE query on an associated object(child) of an object(parent) when parent is updated更新父对象时,活动记录 update_attribute 对对象(父对象)的关联对象(子对象)执行 DELETE 查询
【发布时间】:2012-06-12 13:44:43
【问题描述】:

导轨:3.0.11

Ruby:1.9.3

当我更新父对象时,为什么活动记录 update_attribute 对对象(父对象)的关联对象(子对象)执行 DELETE 查询?

以下是我的课程:

class User < ActiveRecord::Base

  has_many :user_keywords, :dependent => :destroy  
  has_many :keywords, :through => :user_keywords

end

class UserKeyword < ActiveRecord::Base
  belongs_to :user
  belongs_to :keyword
end

class Keyword < ActiveRecord::Base
  has_many :user_keywords
  has_many :users, :through => :user_keywords
end

在前端,每​​个关键字都有一个复选框。

  • 复选框:关键字 1
  • 复选框:关键字 2
  • 复选框:关键字 3
  • 复选框:关键字 4

我第一次选中“关键字 1”和“关键字 2”复选框来更新用户的关键字。

我再次通过选中“关键字 1”和“关键字 3”复选框来编辑用户以更新关联的关键字并更新了用户。 第二个更新删除了我的 USER_KEYWORDS 表中以前的记录。

以下是我的控制台输出,显示正在执行的 DELETE 语句:

  User Load (55.5ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 5 LIMIT 1
  Keyword Load (0.2ms)  SELECT "keywords".* FROM "keywords" WHERE "keywords"."id" IN (1, 3)
  Keyword Load (0.2ms)  SELECT "keywords".* FROM "keywords" INNER JOIN "user_keywords" ON "keywords".id = "user_keywords".keyword_id WHERE (("user_keywords".user_id = 5))
  AREL (0.2ms)  DELETE FROM "user_keywords" WHERE "user_keywords"."user_id" = 5 AND "user_keywords"."keyword_id" = 2
  AREL (0.1ms)  INSERT INTO "user_keywords" ("keyword_id", "user_id", "status", "created_at", "updated_at") VALUES (3, 5, 'f', '2012-06-12 13:15:43.912236', '2012-06-12 13:15:43.912236')

has_many 方法的 :dependent 选项表示 (http://guides.rubyonrails.org/association_basics.html#has_many-association-reference):

4.3.2.6 :依赖

如果您将 :dependent 选项设置为 :destroy,则删除此对象将调用关联对象的 destroy 方法以删除这些对象。如果将 :dependent 选项设置为 :delete_all,则删除此对象将删除关联的对象,而不调用它们的 destroy 方法。如果将 :dependent 选项设置为 :nullify,则删除此对象会将关联对象中的外键设置为 NULL。

当您对关联使用 :through 选项时,此选项将被忽略。 ##

我无法理解这种行为。有人可以详细说明或澄清吗?

【问题讨论】:

    标签: ruby-on-rails-3 activerecord


    【解决方案1】:

    delete 语句只删除了关键字 2 的关联。当您提交带有两个复选框的表单时,系统假定您希望关联这两个项目,但没有其他未选中的项目。因此,当它加载当前的user_keyword 关联时,它看到有一条您没有选择保留的现有记录,因此将其删除。然后它看到有一个新的,所以它创建了一个新的。

    如果您只想添加关系而不删除关系,那么我不建议使用复选框,因为选中复选框意味着添加,但删除选中意味着破坏关系(这就是 rails 在这种情况下所做的)。具有 AJAX 功能的按钮可能更有意义。如果您确实想保留复选框,但不允许 rails 破坏未选中的关系,那么您必须根据参数自己建立关系,而不是依赖 rails 的魔法来为您完成这项工作。

    请注意,这与:dependent 选项无关,这仅仅是由于您在模型和表单中设置的关系。

    【讨论】:

    • 感谢贾斯汀的详细说明。您能指出我提到的复选框行为的文档/资源吗?
    • 看看这里:guides.rubyonrails.org/… 特别是:The collection of join models can be managed via the API. For example, if you assign physician.patients = patients new join models are created for newly associated objects, and if some are gone their rows are deleted. Automatic deletion of join models is direct, no destroy callbacks are triggered. 使用复选框,您实际上是通过 update_attributes 将关键字列表传递给用户。任何缺失的关键字都会被自动删除。
    • 最佳实践是确保在您输入表单时根据该关系是否已经存在预先填充复选框。这样,您必须显式删除一个复选框才能删除该关系。
    • 如果User 验证失败会怎样?它会更新数据库中的user_keywords,但不会保存用户记录,从而导致状态不一致。对此有什么想法吗?
    • @Jignesh 可以在railscasts找到更全面的介绍。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-22
    • 1970-01-01
    • 1970-01-01
    • 2017-12-08
    • 1970-01-01
    相关资源
    最近更新 更多