0

如果关联记录有自己的关联记录,我试图阻止它被删除。Rails 似乎正在颠覆 :dependent => :restrict 选项并执行 DELETE SQL。我错过了什么?

class User < ActiveRecord::Base
  has_many :user_regions
  has_many :events, :through => :user_regions
  has_many :regions, :through => :user_regions
end

class Region < ActiveRecord::Base
  has_many :user_regions
  has_many :events, :through => :user_regions
end

class UserRegion < ActiveRecord::Base
  belongs_to :user
  belongs_to :region

  has_many :events, :dependent => :restrict
end

class Event < ActiveRecord::Base
  belongs_to :user_region, :readonly => true
  has_one :planner, :through => :user_region, :source => :user
  has_one :region, :through => :user_region
end

现在假设我有两个区域 [R1 和 R2],两个用户 [U1 和 U2]。U1 已分配给 R1 和 R2 [作为 UR1 和 UR2],而 U2 已分配给 R2 [作为 UR3]。这给出了总共三个 UserRegions。

此外,我还有事件 E1、E2 和 E3,其中 E1 在 UserRegion UR1 中,E2 在 UserRegion UR2 中,E3 在 UserRegion UR3 中。这给了 U1 两个事件和 U2 一个事件。

应该发生什么:如果我试图删除 U1 对 R2 的分配(即销毁 UR2),我应该得到一个错误,因为 U1 有通过 UR2 的事件。

怎么了:

u1 = User.find(1)
urids = u1.regions.map &:id
 => [1,2]
u1.region_ids = [1]
Region Load (0.3ms)  SELECT "regions".* FROM "regions" WHERE "regions"."id" = ? LIMIT 1  [["id", 1]]
Region Load (0.3ms)  SELECT "regions".* FROM "regions" INNER JOIN "user_regions" ON "regions"."id" = "user_regions"."region_id" WHERE "user_regions"."user_id" = 1
 (0.1ms)  begin transaction
SQL (0.3ms)  DELETE FROM "user_regions" WHERE "user_regions"."user_id" = 1 AND "user_regions"."region_id" = 2
 (2.7ms)  commit transaction
 => [1] 

显然,Rails 没有在被删除的 UserRegion 上执行 :destroy 回调,因为如果我尝试这样做:

UserRegion.find(2).destroy

我会得到一个错误,事务会回滚。

我需要做些什么来确保将 Region id 分配给 User 不会删除 UserRegions?

这里的目标是“编辑用户”表单有一个用于分配区域的复选框列表。应该可以向用户添加区域并删除用户没有事件的区域。

4

2 回答 2

0

也许您可以先搜索关联的记录,然后仅在它们的计数为零时才执行删除代码行?

def destroy
@hgroup = Hgroup.find(params[:id])
  if 'search for associations' == 0
    @hgroup.destroy
      respond_to do |format|
       format.html { redirect_to hgroups_url }
     end
  else
     'do something else'
  end

结尾

尝试类似的东西。

于 2012-06-24T17:13:23.643 回答
0

来自ActiveRecord::Associations 文档的“删除还是销毁?” 部分:

对于 has_many,destroy 将始终调用要删除的记录的 destroy 方法,以便运行回调。但是 delete 将根据 :dependent 选项指定的策略进行删除,或者如果没有给出 :dependent 选项,则它将遵循默认策略。默认策略是:nullify(将外键设置为nil),除了has_many :through,默认策略是delete_all(删除连接记录,不运行它们的回调)。

所以在我上面的用户模型中,我需要改变这个:

class User < ActiveRecord::Base
  has_many :user_regions
  has_many :events, :through => :user_regions
  has_many :regions, :through => :user_regions
end

进入这个:

class User < ActiveRecord::Base
  has_many :user_regions
  has_many :events, :through => :user_regions
  has_many :regions, :through => :user_regions, :dependent => :destroy
end

如果用户仍然有通过 UserRegion 的事件,这有效地防止了 UserRegion 被删除。如果尝试这样做,将引发 ActiveRecord::DeleteRestrictionError。

在控制器级别处理此错误并设置我的视图以便永远不会遇到这种情况当然是另一回事。

于 2012-06-24T19:51:23.043 回答