2

我有三个 activerecord 类:Klass、Reservation 和 Certificate 一个 Klass 可以有许多预订,每个预订可能有一个证书

定义如下...

class Klass < ActiveRecord::Base
  has_many :reservations, dependent: :destroy, :autosave => true  
  has_many :certificates, through: :reservations
  attr_accessible :name

  def kill_certs
    begin
      p "In Kill_certs"
      self.certificates.destroy_all
      p "After Destroy"
    rescue Exception => e
      p "In RESCUE!"
      p e.message
    end  
  end

end

class Reservation < ActiveRecord::Base
  belongs_to :klass
  has_one :certificate, dependent: :destroy, autosave: true
  attr_accessible :klass_id, :name
end

class Certificate < ActiveRecord::Base
  belongs_to :reservation
  attr_accessible :name
end

我希望能够通过调用 Klass#kill_certs(上图)来删除/销毁 klass 控制器中特定 klass 的所有证书

但是,我收到一条消息异常:

"In RESCUE!"
"Cannot modify association 'Klass#certificates' because the source 
reflection class 'Certificate' is associated to 'Reservation' via :has_one."

我(还尝试将预订类更改为“has_many :certificates”,然后错误是...

"In RESCUE!"
"Cannot modify association 'Klass#certificates' because the source reflection
 class 'Certificate' is associated to 'Reservation' via :has_many."

奇怪的是,我可以从控制台执行 Klass.first.certificates 并检索第一类的证书,但我不能在不创建错误的情况下执行 Klass.first.certificates.delete_all。我错过了什么吗?

这是唯一的方法..

Klass.first.reservations.each do |res|
  res.certificate.destroy
end

谢谢你的帮助。

4

1 回答 1

4

RoR文档对此有明确的解释(仅为 TLDR 阅读粗体):

从关联中删除

什么会被删除?

这里有一个潜在的陷阱: has_and_belongs_to_many 和 has_many :through 关联在连接表中都有记录,以及关联的记录。那么当我们调用其中一种删除方法时,究竟应该删除什么?

答案是假设删除关联是关于删除所有者和关联对象之间的链接,而不是关联对象本身。 因此,使用 has_and_belongs_to_many 和 has_many :through,连接记录将被删除,但关联记录不会。

如果您考虑一下,这是有道理的:如果您要调用 post.tags.delete(Tag.find_by(name: 'food')) 您会希望从帖子中取消链接“food”标签,而不是标记本身要从数据库中删除。

但是,有些例子表明这种策略没有意义。例如,假设一个人有很多项目,每个项目都有很多任务。如果我们删除了某人的一项任务,我们可能不希望删除该项目。在这种情况下,delete 方法实际上不会起作用:它只能在连接模型上的关联是belongs_to 时使用。在其他情况下,您应该直接对关联的记录或 :through 关联执行操作。

对于常规的 has_many,“关联记录”和“链接”之间没有区别,因此对于删除的内容只有一种选择。

使用 has_and_belongs_to_many 和 has_many :through,如果你想自己删除关联的记录,你总是可以按照 person.tasks.each(&:destroy) 的方式做一些事情

所以你可以这样做:

self.certificates.each(&:destroy)
于 2013-10-05T21:39:21.433 回答