在Rails模型中删除一个关系
在Rails模型中删除关系的原因是要保留报告对象(report),但是将剂量(dosage)从数据库中删除,并将其标记为“deleted”。如果这是您的用例,首先需要了解的是,报告对象将保留,无论剂量是否被删除,因为它们之间是一对多的关系(1-*)。然而,您需要了解delete
和destroy
之间的区别,stackoverflow社区在这里回答了这个问题:Difference between Destroy and Delete。
作为额外的提示,可以了解一下Ruby中的shebang(!)方法以及何时使用它,例如delete!
和destroy!
。
不,我不想从数据库中删除任何内容。我希望在结束时report.dosages.size为0。我不明白为什么Rails会设置destroyed标志,而不是删除对象。
在Rails模型中删除关系的问题出现的原因是因为在调用destroy
方法时,并没有将关系对象持久化到数据库中。解决方法是在调用build
方法之后,需要调用save
方法将关系对象持久化到数据库中,然后再调用destroy
方法删除关系对象。
具体的解决方法如下:
report = Report.first dosage = report.dosages.build dosage.save report.dosages.size # 1 report.dosages.first.destroy report.dosages.size # 0
使用这个方法可以解决问题。同时,还可以参考ActiveRecord_Associations_CollectionProxy::delete的文档获取更多信息。
以下是一个关于该问题的实际示例:
你的场景:
2.4.0 :007 > r.dosages.build => #2.4.0 :008 > r.dosages.size => 1 2.4.0 :009 > r.dosages.first.destroy (0.1ms) begin transaction (0.0ms) commit transaction => # 2.4.0 :010 > r.dosages.size => 1
我建议的解决方法:
2.4.0 :005 > report = Report.first Report Load (0.1ms) SELECT "reports".* FROM "reports" ORDER BY "reports"."id" ASC LIMIT ? [["LIMIT", 1]] => #2.4.0 :006 > report.dosages.count (0.1ms) SELECT COUNT(*) FROM "dosages" WHERE "dosages"."report_id" = ? [["report_id", 1]] => 0 2.4.0 :007 > dosage = report.dosages.build => # 2.4.0 :008 > dosage.save (0.1ms) begin transaction SQL (0.7ms) INSERT INTO "dosages" ("created_at", "updated_at", "report_id") VALUES (?, ?, ?) [["created_at", "2018-07-03 14:06:08.709323"], ["updated_at", "2018-07-03 14:06:08.709323"], ["report_id", 1]] (0.9ms) commit transaction => true 2.4.0 :009 > report.dosages.size (0.2ms) SELECT COUNT(*) FROM "dosages" WHERE "dosages"."report_id" = ? [["report_id", 1]] => 1 2.4.0 :010 > report.dosages.first.destroy Dosage Load (0.2ms) SELECT "dosages".* FROM "dosages" WHERE "dosages"."report_id" = ? ORDER BY "dosages"."id" ASC LIMIT ? [["report_id", 1], ["LIMIT", 1]] (0.0ms) begin transaction SQL (0.3ms) DELETE FROM "dosages" WHERE "dosages"."id" = ? [["id", 1]] (0.8ms) commit transaction => # 2.4.0 :011 > report.dosages.size (0.2ms) SELECT COUNT(*) FROM "dosages" WHERE "dosages"."report_id" = ? [["report_id", 1]] => 0
以上是解决该问题的方法。在这个示例中,关联关系被设置为:
dosage.rb class Dosage < ApplicationRecord belongs_to :report end report.rb class Report < ApplicationRecord has_many :dosages end
同时还需要进行以下迁移:
class ManyDosagesToReport < ActiveRecord::Migration[5.0] def change add_column :dosages, :report_id, :integer end end
实际上,如果你尝试对构建但尚未持久化的dosage
对象进行持久化,Rails会报错:
RuntimeError: can't modify frozen Hash
这是由于destroyed
属性造成的。