关于rails上的ruby:删除has_many:通过关联不会更改模型的updated_at属性

Removing has_many :through association doesn't change model's updated_at attribute

我很难通过在CasinoAmenity上获得has_many Amenities的Casino模型来更新updated_at列。在添加娱乐设施时,赌场的updated_at列会正确更新,但在删除娱乐设施时,不会更新。

这是我的(简体)型号:

casino.rb

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

amenity_casino.rb

1
2
3
4
class AmenityCasino < ActiveRecord::Base
  belongs_to :casino, :touch => true
  belongs_to :amenity, :touch => true
end

amenity.rb

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

现在进入控制台。检查初始的update_at时间。

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

为娱乐场增添便利设施。

1
2
> 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">]

确认关联已保存到数据库

1
2
> 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时间已按预期进行了更改。

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

现在,让我们从赌场中删除该便利设施。

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

现在确保它能正常运行数据库

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

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

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

如您所见,这与我们从娱乐场移除洗手间之前的情况相同。我也曾尝试在AmenityCasino上使用before_destroy过滤器来接触赌场,但这似乎并不能解决问题。

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

Rails版本为3.2.11


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

应该是这样的:

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

但是,这不能解决这里的问题。参照这个(有些旧)的答案,看来问题在于联接表条目被删除而不是被销毁,并且删除不会触发touch方法,因此updated_at不会被更新。

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

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

我已经对此进行了测试,并且似乎可以正常工作:

1
2
3
4
5
6
7
8
9
10
11
12
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

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


在我说这之前,我必须指出,我不确定这在Rails 3.2中是否有效,但是我确定它在Rails 4中是否有效。

现在我知道已经回答了这个问题,但是仅供将来参考,而不是

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

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

1
> Casino.find(5).amenities.destroy_all