1

Rails 3.2アソシエーションとPostgreSQL外部キーの微妙な違いに出くわしましたが、それを管理するための最良の方法を確実に理解したいと思います。

応答しているメッセージを追跡するMessageクラスを想定します。「from」メッセージを削除しても、チェーン内の残りのメッセージは削除されないため、:dependent => :destroy句はありません。

class Message < ActiveRecord::Base
  # from_message_id self-reference
  has_many   :from_messages, :foreign_key => "from_message_id", 
             :class_name => "Message", :inverse_of => :from_message
  belongs_to :from_message, 
             :class_name => "Message", :inverse_of => :from_messages

  attr_accessible :from_message_id, subject, body
end

ここで、2つのリンクされたメッセージを作成し、最初のメッセージを削除すると、Railsはメッセージが存在しないことを報告するだけです。

m1 = Message.create
m2 = Message.new
m2.from_message = m1
m2.save
m1.destroy
m2.from_message
=> nil

ただし、移行からデータベースに実際の外部キー制約も追加すると、次のようになります。

execute "ALTER TABLE messages ADD CONSTRAINT messages_from_message_fk 
         FOREIGN KEY (from_message_id)  REFERENCES messages(id);"

次に、キーがまだ使用されているため、かなり厄介な中止が発生します。

m1 = Message.create
m2 = Message.new
m2.from_message = m1
m2.save
m1.destroy
=> ActiveRecord::InvalidForeignKey: PG::Error: ERROR:  update or delete on table 
"messages" violates foreign key constraint "messages_from_message_fk" on 
table "messages"
DETAIL:  Key (id)=(2) is still referenced from table "messages".

これらの結論は正しいですか?

  • Railsはhas_many、およびを使用しbelongs_toて、どのフィールドがどの外部キーを保持しているかを追跡します。「親」レコードを削除する場合、子レコードが孤立しないという検証はありません。

  • 外部キー制約のあるPostgreSQLでは、親が削除される前に、すべての子が親から「リンク解除」されている必要があります。外部キーがnull可能である限り、これは、親を削除する前に子の外部キーをnullに設定することで実現できます。

私の場合、孤児を許可したいと思います。データベースの制約を忘れたほうがいいのでしょうか、それとも、親が削除されたときにデータベースの制約を保持してレコードのリンクを解除することに価値があるのでしょうか。

4

1 に答える 1

0

私の場合、孤児を許可したいと思います。データベースの制約を忘れたほうがいいのでしょうか、それとも、親が削除されたときにデータベースの制約を保持してレコードのリンクを解除することに価値があるのでしょうか。

PostgreSQLでは、外部キー制約を削除してからON DELETE SET NULLを使用してテーブルを再度追加することにより、テーブルを変更します。この場合、削除は外部キーをnullに設定することにカスケードされ、孤立したものを許可します。

于 2013-04-02T11:03:48.760 に答える