Postgres外键冲突错误:在表上插入或更新...违反外键约束

时间:2016-06-26 20:30:59

标签: postgresql ruby-on-rails-4 rspec

我有一个网络应用程序,其中我在两个表之间有以下关系:一个主题和类别表,其中一个类别有很多主题,一个主题属于一个类别。

class Topic < ActiveRecord::Base
    has_many :comments, dependent: :destroy
    belongs_to :category
    belongs_to :user
    validates :subject, :body, :user_id, :category_id, presence: true

    private

    def self.find_by_id(params)
        if params[:topic_id]
            find(params[:topic_id])
        else
            find(params[:id])
        end
    end

    def self.build_topic_comment(params, comment_params)
        @topic = Topic.find_by_id(params)
        @topic.comments.build(comment_params)
    end

    def self.load_comments(topic)
        topic.comments.build
    end
end


class Category < ActiveRecord::Base
    has_many :topics, dependent: :destroy
    belongs_to :user
    validates :name, :user_id, presence: true

    private

    def self.find_by_id(params)
        if params[:category_id]
            find(params[:category_id])
        else
            find(params[:id])
        end
    end

    def self.load_topics_desc(category)
        category.topics.order(created_at: :desc)
    end

    def self.build_category_topic(params, topic_params)
        @category = Category.find_by_id(params)
        @category.topics.build(topic_params)
    end
end

我添加了通过更新主题的外键(称为类别ID)将主题移动到其他类别的功能。这是通过我自己编写的管理面板完成的,它工作正常。当我检查主题索引页面时,他的类别列确实已更新。

问题是我创建的rspec测试失败并给出以下错误:

Admin::TopicsController with administrator access PATCH #update with valid attributes updates a topic
     Failure/Error: if @topic.update(topic_params)

     ActiveRecord::InvalidForeignKey:
       PG::ForeignKeyViolation: ERROR:  insert or update on table "topics" violates foreign key constraint "fk_rails_d5d593e6f0"
       DETAIL:  Key (category_id)=(3) is not present in table "categories".
       : UPDATE "topics" SET "subject" = $1, "body" = $2, "category_id" = $3, "updated_at" = $4 WHERE "topics"."id" = $5
     # ./app/controllers/admin/topics_controller.rb:19:in `update'
     # /Users/Beno/.rvm/gems/ruby-2.2.2/gems/devise-4.1.1/lib/devise/test_helpers.rb:19:in `block in process'
     # /Users/Beno/.rvm/gems/ruby-2.2.2/gems/devise-4.1.1/lib/devise/test_helpers.rb:75:in `catch'
     # /Users/Beno/.rvm/gems/ruby-2.2.2/gems/devise-4.1.1/lib/devise/test_helpers.rb:75:in `_catch_warden'
     # /Users/Beno/.rvm/gems/ruby-2.2.2/gems/devise-4.1.1/lib/devise/test_helpers.rb:19:in `process'
     # ./spec/controllers/admin/topics_controller_spec.rb:79:in `block (5 levels) in <top (required)>'
     # ------------------
     # --- Caused by: ---
     # PG::ForeignKeyViolation:
     #   ERROR:  insert or update on table "topics" violates foreign key constraint "fk_rails_d5d593e6f0"
     #   DETAIL:  Key (category_id)=(3) is not present in table "categories".
     #   ./app/controllers/admin/topics_controller.rb:19:in `update'

rspec测试文件:

require 'rails_helper'

RSpec.describe Admin::TopicsController, type: :controller do
    describe 'with administrator access' do
        let(:valid_attributes) { attributes_for(:topic) }
        let(:invalid_attributes) { attributes_for(:topic, category_id: nil) }
        let(:updated_attributes) { attributes_for(:topic, category_id: 3) }

        before(:each) do
            @topic = create(:topic)
            admin = create(:admin)
            sign_in admin
        end

        describe 'GET #index' do
            it 'renders the index template' do
                get :index
                expect(response).to render_template(:index)
            end

            it 'loads all the topics in the database' do
                get :index
                expect(assigns(:topics)).to eq([@topic])
            end
        end

        describe 'GET #show' do
            it 'renders the show template' do
                get :show, id: @topic
                expect(response).to render_template(:show)
            end

            it 'retrieves a topic from the database' do
                get :show, id: @topic
                expect(assigns(:topic)).to eq(@topic)
            end

            it 'loads the topics comments' do
                topic = create(:topic_with_comments)
                get :show, id: topic
                expect(topic.comments.length).to eq(5)
            end
        end

        describe 'GET #edit' do
            it 'renders the edit template' do
                get :edit, id: @topic
                expect(response).to render_template(:edit)
            end

            it 'retrieves a topic from the database' do
                get :edit, id: @topic
                expect(assigns(:topic)).to eq(@topic)
            end
        end

        describe 'PATCH #update' do
            context 'with valid attributes' do
                it 'finds a topic in the database' do
                    get :edit, id: @topic
                    expect(assigns(:topic)).to eq(@topic)
                end

                it 'updates a topic' do
                    patch :update, id: @topic, topic: updated_attributes
                    @topic.reload
                    expect(assigns(:topic)).to eq(3)
                end

                it 'redirects to admin topic path' do
                    patch :update, id: @topic, topic: updated_attributes
                    expect(response).to redirect_to(admin_topics_path)
                end
            end

            context 'with invalid attributes' do
                it 'does not update a topic'
                it 're-renders the edit template'
            end
        end

        describe 'GET #new' do
            it 'renders the new template'
            it 'creates a new topic'
        end

        describe 'PUT #create' do
            context 'with valid attributes' do
                it 'saves a topic in the database'
                it 'redirects to created topic'
            end

            context 'without valid attributes' do
                it 'does not save a topic in the database'
                it 're-renders the new template'
            end
        end

        describe 'DESTROY #delete' do
            it 'finds a topic in the database'
            it 'deletes a topic from the database'
            it 'redirects to admin topics index'
        end
    end
end

管理员主题控制器:

class Admin::TopicsController < Admin::BaseController

    def index
        @topics = Topic.all
    end

    def show
        @topic = Topic.find_by_id(params)
    end

    def edit
        @topic = Topic.find_by_id(params)
        @topic_options = Topic.all.collect { |topic| [ topic.category.name, topic.category_id ] }.uniq
    end

    def update
        @topic = Topic.find_by_id(params)

        if @topic.update(topic_params)
            redirect_to admin_topic_path(@topic), notice: 'Topic updated successfully'
        else
            render :edit
        end
    end

    private

    def topic_params
        params.require(:topic).permit(:subject, :body, :category_id)
    end

end

有人可以指出我为什么测试失败并且应用程序运行正常的正确方向?

谢谢!

0 个答案:

没有答案