Ошибка PostsControllerTest с простой программой Ruby on Rails - PullRequest
0 голосов
/ 20 июня 2019

Полный код на GitHub, https://github.com/Marium36/blog

Я прохожу онлайн-курс по Ruby on Rails, который поможет нам создать простое приложение для блога.

Запуск этого в Ubuntu 18.04

Следующие команды работают

> rails new blog
> cd blog
> rails generate scaffold Post title:string body:text
> rails generate scaffold Comment post:references body:text
> rake db:migrate
> rake routes
> rails server

Как только я запускаю это (по курсу)

> rake db:test:load
> rake test

Я получаю ошибку

Run options: --seed 62159

# Running:

.E

Error:
PostsControllerTest#test_should_destroy_post:
ActiveRecord::InvalidForeignKey: SQLite3::ConstraintException: FOREIGN KEY constraint failed
    app/controllers/posts_controller.rb:57:in `destroy'
    test/controllers/posts_controller_test.rb:43:in `block (2 levels) in <class:PostsControllerTest>'
    test/controllers/posts_controller_test.rb:42:in `block in <class:PostsControllerTest>'


rails test test/controllers/posts_controller_test.rb:41

............

Finished in 7.151961s, 1.9575 runs/s, 2.2371 assertions/s.
14 runs, 16 assertions, 0 failures, 1 errors, 0 skips

1 Ответ

3 голосов
/ 21 июня 2019

Ошибка, с которой вы столкнулись (сбой ограничения внешнего ключа), говорит о том, что у вас есть ограничение внешнего ключа в вашей базе данных, которое не выполняется при запуске какого-то определенного фрагмента кода.

Что такое внешний ключ? * В реляционных базах данных - таких как 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

Сэто изменение вашего теста должно быть успешным, потому что оно удалит комментарии, а также сообщение в той же транзакции, предотвращая сбой ограничения внешнего ключа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...