0

I've got in this current situation two models; Country and Province and I'm trying to create a relationship between these two models in a 1:M relationship. The problem I'm having is I can't get a migration to correctly create the relationship when I generate the models as such:

class CreateCodeTableCountries < ActiveRecord::Migration[7.0]
  def change
    create_table :countries, primary_key: "country_code",  id: { type: :string, limit: 2 }, force: :cascade do |t|
      t.string :screen_label, limit: 80, null: false
      t.boolean :is_active, default: true, null: false
      t.integer :display_order, limit: 2, default: 10, null: false
    end
  end
end

class CreateCodeTableProvinces < ActiveRecord::Migration[7.0]
  def change
    create_table :provinces, primary_key: "province_code", id: { type: :string, limit: 20 }, force: :cascade do |t|
      t.string :country_code, limit: 20, null: false
      t.references :countries
      t.string :screen_label, limit: 80, null: false
      t.boolean :is_active, default: true, null: false
      t.integer :display_order, limit: 2, default: 10, null: false
    end
  end
end

In this instance the migration creates the table but not the relationship between Country and Province. If I try and create a new Province

country.provinces.create!(province_code: item["provinceCode"], country_code: country["country_code"], screen_label: item["screenLabel"], is_active: item["isActive"], display_order: item["displayOrder"])

doing so results in an error that doens't make much sense given I've specified a primary key on the Country model as country_code:

ActiveModel::UnknownAttributeError: unknown attribute 'country_id' for CodeTable::Province.

          raise UnknownAttributeError.new(self, k.to_s)
          ^^^^

however if I instead do the following I have no problems, the Province is created successfully, but again there's no reference and relationship between the two models

CodeTable::Province.create!(province_code: item["provinceCode"], country_code: country["country_code"], screen_label: item["screenLabel"], is_active: item["isActive"], display_order: item["displayOrder"])

Where things start making a bit more sense is if I create my Province migration as follows:

class CreateCodeTableProvinces < ActiveRecord::Migration[7.0]
  def change
    create_table :provinces, primary_key: "province_code", id: { type: :string, limit: 20 }, force: :cascade do |t|
      t.string :country_code, limit: 2, null: false
      t.string :screen_label, limit: 80, null: false
      t.boolean :is_active, default: true, null: false
      t.integer :display_order, limit: 2, default: 10, null: false
    end

    add_foreign_key :provinces, :countries, column: "country_code", primary_key: "country_code", name: "country_province_fk"
    # add_foreign_key :provinces, :countries, column: :country_code, primary_key: "country_code"
  end
end

This creates the table, and setups the foreign key correctly between the two tables, that is until I again try to create a new Province and I keep getting the same error message about the unknown attribute 'country_id'

In my Country and Province models they've been defined as:

class CodeTable::Country < ApplicationRecord
    self.primary_key = "country_code"

    has_many :provinces
end

and

class CodeTable::Province < ApplicationRecord
  self.primary_key = "province_code"

  belongs_to :country,  foreign_key: "country_code"
end

At this point I have no idea what it is that I'm doing wrong, or why rails insists on using an id that isn't defined or created.

I also understand this isn't the "rails" way but at the same time this is how my database is designed, and this is a common pattern that I don't want to change.

Marqueone
  • 1,165
  • 2
  • 14
  • 33

1 Answers1

1

In the has_many model shouldn't it be something like:

has_many :provinces, foreign_key: "country_code"

I thought you needed to tell it what the foreign key would be in the table it will be looking at for the has_many relation. Hope that helps.

Beartech
  • 6,173
  • 1
  • 18
  • 41