【问题标题】:Removing has_many :through association doesn't change model's updated_at attribute删除 has_many :through 关联不会改变模型的 updated_at 属性
【发布时间】:2013-01-30 01:51:12
【问题描述】:

我很难让 updated_at 列更新通过 CasinoAmenity 拥有_many 便利设施的赌场模型。赌场的 updated_at 列在添加设施时会正确更新,但在移除时不会。

这是我的(简化的)模型:

赌场.rb

class Casino < ActiveRecord::Base
  has_many :amenity_casino, :dependent => :destroy
  has_many :amenities, :through => :amenity_casino
end

amenity_casino.rb

class AmenityCasino < ActiveRecord::Base
  belongs_to :casino, :touch => true
  belongs_to :amenity, :touch => true
end

amenity.rb

class Amenity < ActiveRecord::Base
  has_many :amenity_casinos, :dependent => :destroy
  has_many :casinos, :through => :amenity_casinos
end

现在到控制台。检查初始 updated_at 时间。

> Casino.find(5).updated_at
=> Wed, 30 Jan 2013 00:30:04 UTC +00:00

为赌场增添便利设施。

> Casino.find(5).amenities << Amenity.first
=> [#<Amenity id: 1, name: "asdf", weight: "", created_at: "2012-11-10 02:29:14", updated_at: "2013-01-30 01:29:14", description: "asdf">]

确认关联已保存到数据库中

> Casino.find(5).amenities
=> [#<Amenity id: 1, name: "asdf", weight: "", created_at: "2012-11-10 02:29:14", updated_at: "2013-01-30 01:29:14", description: "asdf">]

我们可以看到该赌场的 updated_at 时间已按预期更改。

> Casino.find(5).updated_at
=> Wed, 30 Jan 2013 01:29:14 UTC +00:00

现在让我们从赌场中移除该设施。

> Casino.find(5).amenities = []
=> []

现在确保它可以正常访问数据库

> Casino.find(5).amenities
=> []

现在让我们检查一下赌场的 updated_at 列...

> Casino.find(5).updated_at
=> Wed, 30 Jan 2013 01:29:14 UTC +00:00

如您所见,这与我们从赌场移除设施之前的情况相同。我还尝试在 AmenityCasino 上使用 before_destroy 过滤器来触摸赌场,但这似乎没有奏效。

我很想听听这里是否有人有任何解决方案。如果这很重要,我将使用 ActiveAdmin 来管理所有内容。

Rails 版本是 3.2.11

【问题讨论】:

  • 这确实很奇怪。

标签: ruby-on-rails ruby-on-rails-3.2 rails-activerecord


【解决方案1】:

首先,您在Casino 模型中的两个位置缺少amenity_casino 末尾的“s”。

应该是这样的:

class Casino < ActiveRecord::Base
  has_many :amenity_casinos, :dependent => :destroy
  has_many :amenities, :through => :amenity_casinos
end

不过,这并不能解决这里的问题。参考this (somewhat old) SO answer,看起来问题是连接表条目被删除而不是销毁,并且删除不会触发touch方法,因此updated_at没有更新。

要解决这个问题,您可以在关联中添加 :after_remove 选项并传递 proc 以在模型本身上调用 touch

has_many :amenity_casinos, :dependent => :destroy
has_many :amenities, :through => :amenity_casinos,\
         :after_remove => proc { |a| a.touch }

我已经对此进行了测试,它似乎可以工作:

Casino.find(5).updated_at
#=> Wed, 30 Jan 2013 03:21:29 UTC +00:00
Casino.find(5).amenities << Amenity.first
#=> [#<Amenity id: 1, name: nil, created_at: "2013-01-30 02:48:49", updated_at: "2013-01-30 03:25:23">]
Casino.find(5).amenities
#=> [#<Amenity id: 1, name: nil, created_at: "2013-01-30 02:48:49", updated_at: "2013-01-30 03:25:23">]
Casino.find(5).updated_at
#=> Wed, 30 Jan 2013 03:25:23 UTC +00:00
Casino.find(5).amenities = []
#=> []
Casino.find(5).updated_at
#=> Wed, 30 Jan 2013 03:27:33 UTC +00:00

您可以看到时间戳已更改。如果您还想更新 updated_at 属性,则必须对 Amenity 模型执行相同的操作。

【讨论】:

  • 感谢您的回答!明天我会试一试,让每个人都知道它是怎么回事。我有一种感觉是因为删除而不是破坏,但我不确定如何改变这种行为,或者解决它。您认为 Rails 核心团队是否有兴趣在这种情况下更改触及删除的功能(或将其更改为销毁)以实现此处的“预期”结果?
  • 是的,我也想过。老实说,我对内部结构了解得不够多,不知道他们这样做是否有充分的理由。但值得在 github 页面上发布一个问题,看看他们的想法。
  • 这很好用。再次感谢!我希望它在未来也能对其他人有所帮助。
【解决方案2】:

在我说这个之前,我必须注意我不确定这在 Rails 3.2 中是否有效,但我确信它在 Rails 4+ 中有效

现在我知道这已得到解答,但仅供将来参考,而不是

> Casino.find(5).amenities = []

您可以使用destroy_all 方法,该方法将销毁所有join_model 记录和touch 关联(如果您在示例中列出了该选项)并执行适当的回调(用于destroy ) 在join_model 上(在示例中为AmenityCasino

> Casino.find(5).amenities.destroy_all

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-31
    • 2014-06-03
    • 1970-01-01
    • 1970-01-01
    • 2013-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多