代码之家  ›  专栏  ›  技术社区  ›  Grey

删除Rails模型中的关系

  •  1
  • Grey  · 技术社区  · 6 年前

    我使用的是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 回复  |  直到 6 年前
        1
  •  2
  •   Alex.U    6 年前

    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
    

    有关详细信息,请查看文档 ActiveRecord_Associations_CollectionProxy::delete


    第一, ActiveRecord::Relation#build 是的别名 ActiveRecord::Relation#new :

    可以将新对象实例化为空对象(不传递构造参数)或具有属性但尚未保存的预设对象(传递具有匹配关联表列名的键名的哈希)。在这两种情况下,有效的属性键都是由关联表的列名决定的,因此不能有不属于表列的属性。

    如果希望删除第一个元素,则必须将其持久化到数据库中,否则Rails将完全按照您的经验进行操作,请设置destroyed标志。

    尝试以下顺序:

    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 属性。

        2
  •  0
  •   Kenigbolo    6 年前

    如果我理解正确,您希望从数据库中删除剂量,因此将剂量呈现为 deleted 但是否仍要保留报表对象?如果这是您的用例,那么首先您应该知道报告将保持不变,不管删除的剂量是多少,因为它是1-*(一对多关系),但是您需要查看 delete destroy StackOverflow社区在这里帮助回答 Difference between Destroy and Delete

    作为奖励,一定要看看舍邦!Ruby中的方法以及何时使用它,例如 delete! destroy!