Polymorphic Association Rails : Different primary_keys types (id & uuid)
Asked Answered
K

4

5

I would like to define a polymorphic table. My problem being that one table's primary_key is of type uuid(string) and the other id(integer). I thought maybe having a model_able_id and a model_able_uuid varying depending on the model_type but i cannot figure that out and it would probably break tons of activerecord features for polymorphic.

Some other things i have thought of would be to use STI, but i'm still confused, and, of course, i could migrate ids to uuids and that'd sort me out (but i'd rather not).

Kilo answered 23/1, 2018 at 17:27 Comment(2)
as you said you can use uuid in both the models, this seems a good solution.Iconoclasm
Just for the record, these are related issues on official rails repo: github.com/rails/rails/issues/33407 github.com/rails/rails/issues/33525Lubricous
O
5

Specify the type for the (polymorphic) foreign key in the options. Change :string to :uuid if required.

create_table :table_name do |t|
  t.references :target, type: :string, polymorphic: true, null: false
end

Then both string and integer target_ids are acceptable.

Check the API docs.

Ostrander answered 9/7, 2020 at 10:25 Comment(2)
For Postgres, type: :uuid works for me.Nikkinikkie
Integer ids do not seem to work with the string type (Rails 7.0.8).Collegium
L
1

Was facing same issue, there is no official solution yet, these two issues are open in rails repo about this:

https://github.com/rails/rails/issues/33407

https://github.com/rails/rails/issues/33525

There is a suggestion in one of these issues, it didn't work for me(it was generating both joins, the default one generated by rails which causes failure and one which i defined).

I ended up not using association at all, i defined a method to get the actual records properly with a custom query. I didn't need dependent: destroy otherwise i could have defined a before_destroy method too.

Hope it helps someone.

Lubricous answered 13/9, 2018 at 8:28 Comment(0)
G
0

I had exactly the same problem. My solution modifies the type of the _id field to string.

def change
  add_reference :ratings, :rater, polymorphic: true, index: true
  change_column :ratings, :rater_id, :string
end

I hope it helps.

Girasol answered 14/6, 2018 at 15:21 Comment(1)
Rails join is not casting properly the uuid to string in my case. When i try to access the associationLubricous
C
0

One way of a few to do this is to have more than one polymorphic class with the same purpose that duck type the same, one for ids and one for strings. I'll demonstrate with this Commentable concern.

# bigint id migration
create_table :comments do |t|
  t.references :commentable, polymorphic: true, null: true
  ...
end

# string id migration
create_table :string_id_comments do |t|
  t.references :commentable, type: :string, polymorphic: true, null: true
  ...
end

Define models for StringIdComments and Comments. They could share code through a concern or through extension. The Commentable concern now needs to decide which to use:

module Commentable
  extend ActiveSupport::Concern
  included do
    if columns_hash[primary_key].type == :integer
      has_many :comments, as: :commentable, dependent: :destroy
    else
      has_many :comments, as: :commentable, class_name: 'StringIdComments', dependent: :destroy
    end
  end
end

If you wished to query through Comment, this has the downside of having two tables which could be eliminated by using these as through tables to the actual comment. I haven't tested, but it might also be solved by having two keys in a single polymorphic class, a string and a bigint, and specifying the key in the has_.

Collegium answered 11/10, 2023 at 16:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.