Область применения 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
Благодаря объему рельсов, чтобы проверить, если ассоциация не существует
Я просто добавил к этому ответу необходимую фильтрацию для полиморфной ассоциации.
Если у кого-то есть лучшее решение, не стесняйтесь добавлять, и я приму это вместо моего собственного.