2

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"
Eyeslandic
  • 14,553
  • 13
  • 41
  • 54
Noriaki Takamizawa
  • 887
  • 1
  • 10
  • 25
  • does your model have `company_bag_target_id`? – Md. Farhan Memon Jun 01 '17 at 07:35
  • Could you add your factories here? I think that in this line `let(:company_bag) { FactoryGirl.create(:some_company_bag) }` you create company bag with company_ids of companies that don't exist in database. – Bartosz Bonisławski Jun 01 '17 at 07:46
  • @Md.FarhanMemon there's no `company_bag_target_id`. I appended table definition above. – Noriaki Takamizawa Jun 01 '17 at 08:28
  • @BartoszBonisławski thanks for the advise. I appended factory definition. Could you examine it? – Noriaki Takamizawa Jun 01 '17 at 08:34
  • @BartoszBonisławski So, how should I create company_ids of companies virtually? – Noriaki Takamizawa Jun 01 '17 at 08:55
  • try providing foreign_key, `has_many :targets, class_name: "CompanyBagTarget", foreign_key: 'company_bag_id'` or `foreign_key: 'company_id'` – Md. Farhan Memon Jun 01 '17 at 09:02
  • @Md.FarhanMemon Thank you for the advise. Unfortunately, CompanyBagTaget has multi primary key like company_bag_id and company_id. For that reason, I got following warning. WARNING: Active Record does not support composite primary key. company_bag_targets has composite primary key. Composite primary key is ignored. How should I do in this case? – Noriaki Takamizawa Jun 01 '17 at 09:09
  • https://stackoverflow.com/questions/24642005/rails-association-with-multiple-foreign-keys – Md. Farhan Memon Jun 01 '17 at 09:20
  • I was wrong assuming that company_ids come from model and didn't see it comes from parameter. You get them from parsing ` target_ids: "1_インテリジェンステスト株式会社,21_グローバルウォーカーズ株>式会社,33_株式会社コーデセブン"` . You assume that you have companies with id 1, 21 and 33 in database. I think you should generate that string and use ids of existing companies – Bartosz Bonisławski Jun 01 '17 at 09:20
  • @BartoszBonisławski Thanks. I do agree with you. But I don't know how. Could you tell me how to generate table data on the fly. – Noriaki Takamizawa Jun 01 '17 at 11:42
  • 1
    OK. You have created 1 company `let(:companies) { FactoryGirl.create(:companies) }`. I think you have incorrectly used plular for naming and it's just 1 company. If you have created it, you can user `companies.id` to get id of created company and use it in string. It would look like `target_ids: "#{companies.id}_インテリジェンステスト株式会社"`. If you need more companies, you should create them and then use their ids in string. – Bartosz Bonisławski Jun 01 '17 at 12:07
  • 1
    If you want to create more companies, you can do it this way: ``` let(:company1) { FactoryGirl.create(:companies) } let(:company2) { FactoryGirl.create(:companies) } let(:company3) { FactoryGirl.create(:companies) } ``` and then create string like: ` target_ids: "#{company1.id}_インテリジェンステスト株式会社,#{company2.id}_グローバルウォーカーズ株>式会社,#{company3.id}_株式会社コーデセブン"` – Bartosz Bonisławski Jun 01 '17 at 12:09
  • I don't know what's passed in this strings, because I don't know japanese, but I see that you put companies ids and you can put them there like that – Bartosz Bonisławski Jun 01 '17 at 12:10
  • @BartoszBonisławski Appreciated!! I'll try and get back to you when it turns out. – Noriaki Takamizawa Jun 01 '17 at 12:17
  • @BartoszBonisławski when I applied along with your advise, it got fixed like a charm. Thanks a lot. – Noriaki Takamizawa Jun 01 '17 at 16:29
  • Glad that I could help you. Good luck with your work ;) – Bartosz Bonisławski Jun 02 '17 at 05:35

0 Answers0