0

J'ai des enregistrements qui, au lieu d'être supprimés, sont invalidés en créant une entrée dans une table polymorphe record_invalidations.Rails scope par absence d'association has_one polymorphique

La configuration ressemble à ceci:

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 

(Il y a plusieurs classes d'enregistrement, d'où la relation polymorphes.)

Question: Comment puis-je faire un champ d'application, qui renvoie les enregistrements en fonction de la absence des entrées d'une autre classe pointant vers la classe en question.

Le code actuel ne fonctionne pas car le pointeur de relation se trouve dans la table records_invalidations, pas dans la table d'enregistrements.

MISE À JOUR 2

La classe record_invalidation correspond au nom de la table très bien, je pense que le problème est le nom de la colonne. Voici le schéma (simplifié):

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 

MISE À JOUR 3

Je vois savoir pourquoi la première erreur se produisait, alors j'ai enlevé cette mise à jour. Maintenant, je passe le nom de table correct que je rejoins dans la requête SQL, mais j'ai un certain nombre d'arguments incompatibles. Puis-je passer un autre argument à la clause where?

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

donne:

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 
+0

Je ne peux pas vérifier ceci pour le moment d'où le commentaire, mais je pense que vous pouvez faire '.joins (: invalidation). Where ('invalidations.id is null')' ou similaire, laissez-moi savoir si cela fonctionne . –

+0

Plus près! J'ai essayé: self.joins (: infirmation) .où ('invalidations.id est nulle) et a obtenu un très proche sortie de SQL, mais voir une erreur: ActiveRecord :: StatementInvalid: PG :: UndefinedTable: ERREUR : missing Entrée FROM-clause pour la table "invalidation" LINE 1: ... cord_invalidations "." archivable_type "= $ 1 OERE (invalidati ... ^ –

+0

Pouvez-vous essayer' self.table_name = 'records'' (ou quel que soit le nom de la table) dans la classe RecordInvalidation? Peut-être que l'ancienne portée fonctionnerait - dans ce cas? –

Répondre

0

Cela ne peut être le moyen le plus efficace, mais il fonctionne:

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 

Merci à rails scope to check if association does NOT exist

Je viens d'ajouter le filtrage requis pour l'association polymorphique à cette réponse.

Si quelqu'un a une meilleure solution n'hésitez pas à ajouter et je vais accepter cela à la place du mien.