Область применения Rails при отсутствии полиморфной ассоциации has_one

У меня есть записи, которые, вместо того, чтобы быть удаленными, становятся недействительными, создавая запись в полиморфной таблице record_invalidations.

Настройка выглядит следующим образом:

class RecordInvalidation < ActiveRecord::Base
  belongs_to :archivable, polymorphic: true
end


class Record < ActiveRecord::Base
  has_one :invalidation, class_name: "RecordInvalidation", as: :archivable

  def self.default_scope
    where(invalidation: nil)
  end
end

(Есть несколько классов записей, отсюда и полиморфное отношение.)

Вопрос: Как создать область видимости, которая возвращает записи на основе отсутствия записей в другом классе, указывающих на рассматриваемый класс.

Текущий код не работает, потому что указатель отношения находится в таблице records_invalidations, а не в таблице records.

ОБНОВЛЕНИЕ 2

Класс record_invalidation точно соответствует имени таблицы, я думаю, что проблема заключается в имени столбца. Вот (упрощенная) схема:

create_table "records", force: :cascade do |t|
  t.text     "content",        null: false
end

create_table "record_invalidations", force: :cascade do |t|
  t.integer  "archivable_id"
  t.string   "archivable_type"
end

ОБНОВЛЕНИЕ 3

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

self.joins(:invalidation).where('record_invalidations.id is null')

дает:

ActiveRecord::StatementInvalid: PG::ProtocolViolation: ERROR:  bind 
message supplies 1 parameters, but prepared statement "a56" requires 2

: SELECT  "records".* FROM "records" 
    INNER JOIN "record_invalidations" ON 
    "record_invalidations"."archivable_id" = "records"."id" AND 
    "record_invalidations"."archivable_type" = $1 WHERE 
    (record_invalidations.id is null) AND "plans"."id" = $2 LIMIT 1

1 ответ

Возможно, это не самый эффективный способ, но он работает:

def self.default_scope
  # Only show records that were not invalidated
  # Makes a list of all invalidated record ids in a subquery then checks for id
  where.not(:id => RecordInvalidation.select(:archivable_id)
                                     .where(archivable_type: self.name)
                                     .uniq)
end

Благодаря объему рельсов, чтобы проверить, если ассоциация не существует

Я просто добавил к этому ответу необходимую фильтрацию для полиморфной ассоциации.

Если у кого-то есть лучшее решение, не стесняйтесь добавлять, и я приму это вместо моего собственного.

Другие вопросы по тегам