Ошибка, с которой вы столкнулись (сбой ограничения внешнего ключа), говорит о том, что у вас есть ограничение внешнего ключа в вашей базе данных, которое не выполняется при запуске какого-то определенного фрагмента кода.
Что такое внешний ключ? * В реляционных базах данных - таких как MySQL, PostgreSQL или SQLite - у вас обычно есть таблицы данных, которые связывают друг с другом в некоторыхпуть.Обычно строки в этих таблицах ссылаются друг на друга с помощью идентификатора, который называется «ключом».Как и здесь, у вас может быть таблица comments
со столбцом post_id
, который ссылается на столбец id
таблицы posts
.В этом случае post_id
ссылается на иностранный ключ posts.id
.
Что такое ограничение? В реляционных базах данных ограничения обеспечивают способ обеспеченияцелостность ваших данных.Ограничение может выполнять такие действия, как обеспечение того, чтобы столбец price
никогда не был отрицательным (т. Е. Проверка на основе самих данных), обеспечение того, чтобы одно значение было ниже, чем другое в той же строке, или проверка того, что данные полностью соответствуют другой записи в другой таблице.
Соединение вместе: что такое ограничение внешнего ключа? Ограничение внешнего ключа, если вы его еще не сложили, - это просто особый тип ограничения, гарантирующий, что «чужая запись »- строка в таблице, на которую вы ссылаетесь - на самом деле существует.В этом случае comments.post_id
имеет ограничение внешнего ключа для posts.id
, что гарантирует невозможность добавления строки в таблицу comments
с post_id
, которого нет в столбце posts.id
.
Так почему вы получили эту ошибку? Это ваша миграция при создании таблицы comments
:
class CreateComments < ActiveRecord::Migration[6.0]
def change
create_table :comments do |t|
t.references :post, null: false, foreign_key: true
t.text :body
t.timestamps
end
end
end
Обратите внимание на часть foreign_key: true
!Это говорит Rails добавить ограничение внешнего ключа между comments
и posts
для внешнего ключа.
Этот тест не пройден:
test "should destroy post" do
assert_difference('Post.count', -1) do
delete post_url(@post)
end
assert_redirected_to posts_url
end
Он удаляет запись Post
, которая сообщает нам, что в таблице comments
есть строка с post_id
столбец, ссылающийся на сообщение, которое мы пытаемся удалить в этом тесте, отсюда и ошибка.
Что я могу сделать, чтобы это исправить? Во-первых, вы, вероятно, захотите добавить обратную зависимость к вашей модели Post
, например:
class Post < ApplicationRecord
has_many :comments
Затемвы захотите рассказать Rails, как обрабатывать связанные записи при удалении поста.Вы можете сделать это с опцией dependent
, которая принимает несколько опций .Я буду использовать :delete_all
здесь, что говорит Rails использовать один SQL-запрос для удаления всех «зависимых» комментариев (то есть комментариев, которые ссылаются на этот пост) без предварительной загрузки их:
class Post < ApplicationRecord
has_many :comments, dependent: :delete_all
end
Сэто изменение вашего теста должно быть успешным, потому что оно удалит комментарии, а также сообщение в той же транзакции, предотвращая сбой ограничения внешнего ключа.