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 сделает именно то, что вы испытали, установите флаг уничтожения.
Попробуйте следующую последовательность:
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
.