Rails / ActiveRecord: можно ли установить полиморфные отношения с таблицами с разными типами идентификаторов? - PullRequest
0 голосов
/ 21 февраля 2019

Создание многим-многим полиморфным ассоциациям - настоящее головокружение.Я уже провел день на этом, и у меня заканчивается энергия.

У меня есть две модели, Comment и Project.У меня третья модель Badge.Пользователь может отреагировать на комментарий или проект, добавив значок.Комментарии и проекты будут reaction_targets.

. Я думаю, я понимаю, как сделать полиморфную часть «многие ко многим».Проблема в том, что Comment и Project имеют разные типы идентификаторов.Comment индексируется bigint, тогда как Project использует uuid.

Моя таблица соединений называется reactions, через которую Badge указывает на reaction_targets

    class Badge < ApplicationRecord
      has_many :reactions
      has_many :reaction_targets, through: :reactions
    end

Каждая строка в таблице соединений указывает на значок и цель.

    class CreateReactions < ActiveRecord::Migration[5.2]
      def change
        create_table :reactions do |t|
          t.references :reaction_target, polymorphic: true
          t.references :badge
        end
      end
    end

Я установил, что ассоциация с reaction_target является полиморфной.

    class Reaction < ApplicationRecord
      belongs_to :badge
      belongs_to :reaction_target, polymorphic: true
    end

Я указываю Comment за столом соединения.

    class Comment < ApplicationRecord
      has_many :reactions, as: :reaction_target
      has_many :badges, through: :reactions
    end

Все работает правильно:

    > b = Badge.first_or_create(name: 'badge')
    > c = Comment.create
    > c.badges
    #=> []
    > c.badges << b
    #=> (0.2ms)  SAVEPOINT active_record_1...

Однако все обстоит иначе, когда дело доходит до Project.

Я устанавливаюсопоставление таким же образом:

    class Project < ApplicationRecord
      has_many :reactions
      has_many :badges, through: :reactions
    end

Но это не работает одинаково.

    > b = Badge.first_or_create(name: 'badge')
    > p = Project.create
    > p.badges
    #=> #<Badge::ActiveRecord_Associations_CollectionProxy:0x3fdc34cde54c>

Первое, что я вижу, это то, что #badges возвращает объект, отличный от пустогомассив.

И когда я пытаюсь добавить значок в коллекцию, я получаю сообщение об ошибке:

    (1.5ms)  SAVEPOINT active_record_1
    ActiveRecord::StatementInvalid: PG::InFailedSqlTransaction: ERROR:  current transaction is aborted, commands ignored until end of transaction block
    : SAVEPOINT active_record_1
    from /Users/123/.rvm/gems/ruby-2.6.0/gems/activerecord-5.2.2/lib/active_record/connection_adapters/postgresql/database_statements.rb:75:in `async_exec'
    Caused by PG::InFailedSqlTransaction: ERROR:  current transaction is aborted, commands ignored until end of transaction block
    from /Users/123/.rvm/gems/ruby-2.6.0/gems/activerecord-5.2.2/lib/active_record/connection_adapters/postgresql/database_statements.rb:75:in `async_exec'

Я вижу в schema.rb, ожидается, что reaction_target_id будетbigint.

      create_table "reactions", force: :cascade do |t|
        t.string "reaction_target_type"
        t.bigint "reaction_target_id"
        t.bigint "badge_id"
        t.index ["badge_id"], name: "index_reactions_on_badge_id"
        t.index ["reaction_target_type", "reaction_target_id"], name: "index_reactions_on_reaction_target_type_and_reaction_target_id"
      end

Я полагаю, что ошибка выше из-за этого.Можно ли установить полиморфные отношения с таблицами, которые имеют разные типы индексов?Если да, что мне нужно сделать, чтобы иметь возможность добавлять значки в проекты?Если нет, есть ли обходной путь?

1 Ответ

0 голосов
/ 22 февраля 2019

Вы отсутствуете as: :reaction_target в ассоциации has_many :reactions в Project.

class Project < ApplicationRecord
  has_many :reactions, as: :reaction_target
  has_many :badges, through: :reactions
end

Это то, что определяет полиморфную ассоциацию, которую вы объявили как reaction_target.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...