Нарушение внешнего ключа Rails при удалении отношений has_many с зависимым уничтожением

У меня есть простое отношение has_many в модели Rails 4.2:

class Owner < ActiveRecord::Base
  has_many :nested_things, :inverse_of => :owner, :class_name => "Nested::Thing", :dependent => :destroy
end

class Nested::Thing < ActiveRecord::Base
  belongs_to :owner, :inverse_of=>:nested_things
end

Модели значительно сложнее этой, со многими другими отношениями.

Когда сегодня кто-то попытался удалить Owner, это не удалось, потому что в таблице nested_things есть внешний ключ:

> psql annoying_problem

psql (9.5.3)
Type "help" for help.

annoying_problem=# \d+ nested_things
                                                            Table "public.nested_things"
      Column      |            Type             |                           Modifiers                            | Storage  | Stats target | Description 
------------------+-----------------------------+----------------------------------------------------------------+----------+--------------+-------------
 id               | integer                     | not null default nextval('nested_things_id_seq'::regclass)     | plain    |              | 
 owner_id         | integer                     |                                                                | plain    |              | 

 Indexes:
    "nested_things_pkey" PRIMARY KEY, btree (id)
    "ix_nested_things_on_owner_id" btree (owner_id)
Foreign-key constraints:
    "nested_things_owner_id_fk" FOREIGN KEY (owner_id) REFERENCES owners(id)

Когда owner удаляется, это трудоемкий процесс - локально эта конкретная запись сгенерировала файл журнала из 109 000 строк всех выполненных SQL. Однако связь вложенных_вещей приводит к прерыванию всей операции из-за сбоя проверки внешнего ключа.

Вот что кажется соответствующей частью файла журнала:

> grep -n nested_things delete-owner.txt 

....

109762: SQL (1.1ms)  DELETE FROM "nested_things" WHERE "nested_things"."id" = $1  [["id", 8665]]

109836: ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: 
        ERROR:  update or delete on table "owners" violates foreign key 
        constraint "nested_things_owner_id_fk" on table "nested_things"

109837: DETAIL:  Key (id)=(6343) is still referenced from table "nested_things".

Для этого владельца существует только одна запись nested_things. Что может привести к тому, что отношение :dependent => :destroy в Rails удалит зависимое отношение, но не проведет проверку внешнего ключа?


person John Naegle    schedule 13.09.2016    source источник
comment
Я думал, что индекс поврежден, но переиндексация ничего не изменила.   -  person John Naegle    schedule 13.09.2016
comment
Это не первый внешний ключ, который проверяется, когда я пытаюсь удалить его из таблицы напрямую.   -  person John Naegle    schedule 13.09.2016
comment
Удаление другой записи о владельце, которая также имеет вложенные_вещи, работает отлично.   -  person John Naegle    schedule 13.09.2016


Ответы (1)


Оказывается, ответом была область действия по умолчанию для отношений has_many, которая не учитывалась при уничтожении.

person John Naegle    schedule 16.09.2016
comment
Как вы это устранили? Либо вы удалили default_scope, либо решили по-другому? - person x'ES; 02.08.2017
comment
Похоже, я добавил before_destroy в модель, где произошло нарушение внешнего ключа, которое удалило объекты, отсутствующие в области действия по умолчанию. Область по умолчанию была enabled: true, поэтому мой before_destroy удалил все с включенным false или включенным nil: before_destroy { NestedThings.unscoped.where(:owner_id => self.id, :enabled => [nil, false]).destroy_all } - person John Naegle; 16.08.2017