0

I've got two models Wallet and FakeWallet. The Wallet should have one FakeWallet and it should be identified through wallet_type and external_id. It means I need to add references based on wallets external_id field.

Standard migration will be:

# rails g migration addReferencesToFakeWallets wallet:references

class AddReferencesToFakeWallets < ActiveRecord::Migration[6.1]
  def change
    add_reference :fake_wallets, :wallet, null: false, foreign_key: true
  end
end

After rails db:migrate produces me:

t.bigint "wallet_id", null: false
t.index ["wallet_id"], name: "index_fake_wallets_on_wallet_id"

How to bind these two models by external_id instead of wallet_id ?

[EDIT]

# schema.rb after suggestion from comments

  create_table "fake_wallets", force: :cascade do |t|
    t.decimal "balance", default: "0.0"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.bigint "external_id"
    t.index ["external_id"], name: "index_fake_wallets_on_external_id"
  end

  create_table "wallets", force: :cascade do |t|
    t.integer "wallet_type"
    t.string "external_id"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end
mr_muscle
  • 2,536
  • 18
  • 61
  • Does this answer your question? [Specifying column name in a "references" migration](https://stackoverflow.com/questions/13694654/specifying-column-name-in-a-references-migration) – engineersmnky Jul 26 '21 at 15:20
  • https://stackoverflow.com/questions/27809342/rails-migration-add-reference-to-table-but-different-column-name-for-foreign-ke – Deepesh Jul 26 '21 at 15:59
  • @engineersmnky and @deepesh I created a migration `add_reference :fake_wallets, :external, foreign_key: { to_table: :wallets }` and in FakeWallet model I've `belongs_to :external, class_name: 'Wallet'` which corresponds to Wallet model where I've `has_one :fake_wallet, foreign_key: :external_id` in such case how to create a FakeWallet record? I tried to `FakeWallet.create!(external_id: 'BXTEnVEf', balance: 10_000)` but I'm getting an error `RecordInvalid (Validation failed: External must exist)`. I think it means that I cannot pass a string but how to bind those two model based on a string? – mr_muscle Jul 29 '21 at 16:50
  • `FakeWallet.create!(external_id: 'BXTEnVEf', balance: 10_000)` means that it is looking for `Wallet.where(id: 'BXTEnVEf')` is that accurate? It seems off since your id is appears to be a bigint. Can you post your schema (or a boiled down version) for this table? – engineersmnky Jul 29 '21 at 17:38
  • @engineersmnky yes, that's exactly like you wrote (post updated with schema). I know I can do something like `FakeWallet.create!(external: Wallet.find_by(external_id: 'BXTEnVEf'), balance: 10_000)` but I think it's crappy code and it feels like every time I'll do unnecessary query with this `.find_by()`. – mr_muscle Jul 29 '21 at 18:41
  • Your schema is messed up `fake_wallets.external_id` is a "bigint" but `wallets.external_id` is a "string" so you will have to fix this first. It you want the relationship to be external_id to external_id you will also need to change this `belongs_to :external, class_name: 'Wallet'` to `belongs_to :external, class_name: 'Wallet', primary_key: :external_id` and change `Wallet` to `has_one :fake_wallet, foreign_key: :external_id, primary_key: :external_id` so that the relationship knows how to look up the relationship – engineersmnky Jul 29 '21 at 20:47
  • @engineersmnky `wallets.external_id` has to be string because I will be using it for the external API. Let's assume I'll create an additional column inside the `fake_wallets` table - `t.string "identifier"`. Is it possible to create relations between them based on `fake_wallets.identifier` and `wallets.external_id` where both columns are strings? – mr_muscle Jul 29 '21 at 20:55
  • Just change `fake_wallets.external_id` to a "string" through a migration? Overall I am confused by the concept in general since it would make more sense that `wallets.external_id` did not exist at all since this looks like an abuse of the concept of polymorphism – engineersmnky Jul 29 '21 at 20:58
  • @engineersmnky I've changed the `fake_wallets.external_id` to `fake_wallets.identifier` and set is as "string". In `FakeWallet` I've `belongs_to :wallet, foreign_key: :identifier, primary_key: :external_id, optional: true` and in `Wallet` I've `has_one :fake_wallet, foreign_key: :identifier, primary_key: :external_id` and it works but is it a right way to do so? I based on 10y old stackoverflow answer https://stackoverflow.com/a/5331233/10443890 – mr_muscle Jul 29 '21 at 21:30

0 Answers0