I can't figure out how to fix RSpec errors. My apps is like this. There's 3 models, CompanyBag, CompanyBagTarget, Company. CompanyBag is a group of Companies. CompanyBagTarget is association table between CompanyBag and Company. Probably, CompanyBagTarget doesn't match appropriate Company.
Now, RSpec error is here.
1) CompanyBagsController POST #create creates a new ComapnyBag
Failure/Error: t.save!
ActiveRecord::InvalidForeignKey:
Mysql2::Error: Cannot add or update a child row: a foreign key constraint fails (`eiicon`.`company_bag_targets`, CONSTRAINT `fk_bag_targets_company` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`)): INSERT INTO `company_bag_targets` (`company_bag_id`, `company_id`, `display_order`) VALUES (38, 13, 0)
# ./app/models/company_bag.rb:22:in `block in update_targets!'
# ./app/models/company_bag.rb:16:in `each'
# ./app/models/company_bag.rb:16:in `each_with_index'
# ./app/models/company_bag.rb:16:in `update_targets!'
# ./app/controllers/company_bags_controller.rb:52:in `create'
# ./spec/controllers/company_bag_controller_spec.rb:55:in `block (4 levels) in <top (required)>'
# ./spec/controllers/company_bag_controller_spec.rb:54:in `block (3 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# Mysql2::Error:
# Cannot add or update a child row: a foreign key constraint fails (`eiicon`.`company_bag_targets`, CONSTRAINT `fk_bag_targets_company` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`))
# ./app/models/company_bag.rb:22:in `block in update_targets!'
2) CompanyBagsController POST #create creates a new ComapnyBagTarget
Failure/Error: t.save!
ActiveRecord::InvalidForeignKey:
Mysql2::Error: Cannot add or update a child row: a foreign key constraint fails (`eiicon`.`company_bag_targets`, CONSTRAINT `fk_bag_targets_company` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`)): INSERT INTO `company_bag_targets` (`company_bag_id`, `company_id`, `display_order`) VALUES (39, 13, 0)
# ./app/models/company_bag.rb:22:in `block in update_targets!'
# ./app/models/company_bag.rb:16:in `each'
# ./app/models/company_bag.rb:16:in `each_with_index'
# ./app/models/company_bag.rb:16:in `update_targets!'
# ./app/controllers/company_bags_controller.rb:52:in `create'
# ./spec/controllers/company_bag_controller_spec.rb:62:in `block (4 levels) in <top (required)>'
# ./spec/controllers/company_bag_controller_spec.rb:61:in `block (3 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# Mysql2::Error:
# Cannot add or update a child row: a foreign key constraint fails (`eiicon`.`company_bag_targets`, CONSTRAINT `fk_bag_targets_company` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`))
# ./app/models/company_bag.rb:22:in `block in update_targets!'
Next here's model's definitions.
class CompanyBag < ApplicationRecord
has_many :targets, class_name: "CompanyBagTarget"
def update_targets!(company_ids:)
destroy_targets
company_ids.reverse.each_with_index do |id, idex|
t = CompanyBagTarget.new
t.company_bag_id = self.id
t.company_id = id
t.display_order = idex
t.save!
end
end
class CompanyBagTarget < ApplicationRecord
belongs_to :company_target
Next, here's controller.
def create
@bag = CompanyBag.new(bag_params)
@target_ids = params[:company_bag][:target_ids].split(",").map{|n| n.split("_")[0].to_i}
if bag_params[:banner].present?
filename = upload_image
@bag.banner = filename
end
if @bag.save
@bag.update_targets!(company_ids: @target_ids)
redirect_to action: 'index'
else
flash[:alert] = @bag.errors.messages.values[0][0]
@target_ids = params[:company_bag][:target_ids]
render 'new'
end
end
Finally, here's controller's spec.
require 'rails_helper'
RSpec.describe CompanyBagsController, type: :controller do
login_admin
let(:user) { @admin }
let(:company_bag) { FactoryGirl.create(:some_company_bag) }
let(:company_bag_target) { {target_ids: "1_インテリジェンステスト株式会社,21_>グローバルウォーカーズ株式会社,33_株式会社コーデセブン"} }
let(:companies) { FactoryGirl.create(:companies) }
let(:valid_attributes) {
{
label: 1,
banner: "https://s3-ap-northeast-1.amazonaws.com/eiicon.prd.contents/image/bags/6dbd5b5b-f242-4e4a-bcd3-de3edc9ae08d.png",
title: "test title",
description: "test title",
target_ids: "1_インテリジェンステスト株式会社,21_グローバルウォーカーズ株>式会社,33_株式会社コーデセブン"
}
}
describe 'POST #create' do
it 'creates a new ComapnyBag' do
expect{
post :create, params: {company_bag: valid_attributes}, session: valid_session
}.to change(CompanyBag, :count).by(1)
end
it 'creates a new ComapnyBagTarget' do
expect{
post :create, params: {company_bag: valid_attributes}, session: valid_session
}.to change(CompanyBagTarget, :count).by(1)
end
Anyone, please. Thanks in advance.
[Appendix] Next, here's factories.
FactoryGirl.define do
factory :some_company_bag, class: CompanyBag do
label "some label"
banner "https://s3-ap-northeast-1.amazonaws.com/eiicon.prd.contents/image/bags/6dbd5b5b-f242-4e4a-bcd3-de3edc9ae08d.png"
title "Best Company Title Ever!!"
description "Some says description"
html_description "Html desc"
html_keyword "Html Kw"
end
factory :companies, class: Company do
name "複数テスト会社"
name_kana "フクスウテストカイシャ"
premium_status "free"
pr_status_id 0
is_valid 1
after(:create) do |c|
c.staff << FactoryGirl.create(:staff, company_id: c.id)
end
end
end
And tables.
create_table "company_bag_targets", primary_key: ["company_bag_id", "company_id"], force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t|
t.integer "company_bag_id", null: false
t.integer "company_id", null: false
t.integer "display_order", null: false
t.index ["company_id"], name: "fk_bag_targets_company", using: :btree
end
create_table "company_bags", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t|
t.string "label", limit: 100, null: false
t.string "banner", limit: 300
t.string "title", limit: 300
t.text "description", limit: 65535
t.string "html_description", limit: 300
t.string "html_keyword", limit: 300
end
create_table "company", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t|
t.string "name", null: false
t.string "name_kana"
t.integer "prefecture_id"
t.string "url", limit: 1023
t.date "establishment"