删除Rails模型中的关系

时间:2018-07-03 12:56:48

标签: ruby-on-rails ruby activerecord

我正在使用rails 5,并且有一个ActiveRecord“报告”,具有一对多关系,称为“剂量”。

如果是新报告:

report.dosages.size   # Returns 0
report.dosages.build
report.dosages.size   # 1, correct
report.dosages.first.destroy
report.dosages.size  # Still 1 !

我了解它已将剂量设置为“已销毁”,但实际上有可能将其从关系列表中删除吗? (我无法将报告保存到db上)

2 个答案:

答案 0 :(得分:2)

TL; DR:这将满足您的需求:

report = Report.first
dosage = report.dosages.build
report.dosages.size // 1
to_delete_dosage = report.dosages.first
report.dosages.delete(to_delete_dosage)
report.dosages.size // 0

有关更多信息,请检查文档中的https://github.com/yiisoft/yii2/issues/15776


首先,ActiveRecord::Relation#buildActiveRecord_Associations_CollectionProxy::delete的别名:

  

新对象可以实例化为空(不传递任何构造参数)或具有属性的预设,但尚未保存(传递具有与关联表列名匹配的键名的散列)。在这两种情况下,有效的属性键均由关联表的列名确定-因此,您不能拥有不属于表列的属性。

如果要删除第一个元素,则必须将其持久保存到数据库中,否则rails会完全按照您的经验进行操作,请设置destroy flag。

尝试以下顺序:

report = Report.first
dosage = report.dosages.build
dosage.save
report.dosages.size   # 1
report.dosages.first.destroy
report.dosages.size  # 0

我设置了等效于您的问题,这是输出:

您的情况:

2.4.0 :007 > r.dosages.build
 => #<Dosage id: nil, title: nil, created_at: nil, updated_at: nil, report_id: 1>
2.4.0 :008 > r.dosages.size
 => 1
2.4.0 :009 > r.dosages.first.destroy
   (0.1ms)  begin transaction
   (0.0ms)  commit transaction
 => #<Dosage id: nil, title: nil, created_at: nil, updated_at: nil, report_id: 1>
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]]
 => #<Report id: 1, title: nil, date: nil, created_at: "2018-07-03 14:00:08", updated_at: "2018-07-03 14:00:08">
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
 => #<Dosage id: nil, title: nil, created_at: nil, updated_at: nil, report_id: 1>
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
 => #<Dosage id: 1, title: nil, created_at: "2018-07-03 14:06:08", updated_at: "2018-07-03 14:06:08", report_id: 1>
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属性。

答案 1 :(得分:0)

如果我对您的理解正确,您想从数据库中删除剂量,因此将剂量显示为deleted,但仍然希望保留报告对象?如果这是您的用例,那么首先您应该知道该报告将保留,无论其删除的剂量是多少,因为它是1-*(一对多关系),但是您需要查看delete之间的区别和destroy,stackoverflow社区在这里Difference between Destroy and Delete

的帮助下提供了帮助

作为奖励,请看看ruby中的shebang(!)方法以及何时使用它,例如delete! destroy!