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

ここで、2 つのリージョン [R1 と R2]、2 人のユーザー [U1 と U2] があるとします。U1 は [UR1 および UR2 として] R1 と R2 の両方に割り当てられ、U2 は [UR3 として] R2 のみに割り当てられています。これにより、合計 3 つの UserRegions が得られます。

さらに、イベント E1、E2、および E3 があり、E1 は UserRegion UR1 にあり、E2 は UserRegion UR2 にあり、E3 は UserRegion UR3 にあります。これにより、U1 には 2 つのイベントが、U2 には 1 つのイベントが与えられます。

何が起こるべきか: 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

ActiveRecord :: Associationsのドキュメントから、「削除または破棄しますか?」セクション:

has_manyの場合、destroyは常に、削除されるレコードのdestroyメソッドを呼び出して、コールバックが実行されるようにします。ただし、deleteは、:dependentオプションで指定された戦略に従って削除を実行するか、:dependentオプションが指定されていない場合は、デフォルトの戦略に従います。デフォルトの戦略は:nullify(外部キーをnilに設定)です。ただし、デフォルトの戦略がdelete_all(コールバックを実行せずに結合レコードを削除する)であるhas_many:throughを除きます。

したがって、上記のユーザーモデルでは、これを変更する必要がありました。

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 に答える
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 に答える