2013-01-08 4 views
2

J'ai quelques classes ActiveRecord utilisant paper_trail pour le suivi de version. Les classes AR ont des clés primaires personnalisées basées sur leurs noms de tables (par exemple Item.ItemID au lieu de Item.id) afin de respecter les conventions de base de données métier.Comment spécifier une association polymorphe avec des clés primaires personnalisées dans Rails

paper_trail spécifie une relation polymorphes sur chacune des classes chenillés, ainsi:

class TrackedExample < ActiveRecord::Base 
    set_table_name 'TrackedExample' 
    set_primary_key 'TrackedExampleID' 

    # simplified from https://github.com/airblade/paper_trail/blob/master/lib/paper_trail/has_paper_trail.rb 
    has_many :versions 
     :class_name => 'Version' 
     :as   => :item, 
end 

class AnotherTrackedExample 
    set_table_name 'AnotherTrackedExample' 
    set_primary_key 'AnotherTrackedExampleID' 

    has_many :versions 
     :class_name => 'Version' 
     :as   => :item, 
end 

# from https://github.com/airblade/paper_trail/blob/master/lib/paper_trail/version.rb 
class Version 
    belongs_to :item, :polymorphic => true 
    ... 
end 

Si je n'utilise pas les clés primaires sur mesure, l'objet version pourrait faire référence à l'objet suivi (à savoir l'objet dont il est une version) en utilisant Version#item. Lorsque je l'essaie, j'obtiens une erreur:

# This should give back `my_tracked_example` 
my_tracked_example.version.first.item 

=> TinyTds::Error: Invalid column name 'id'.: EXEC sp_executesql N'SELECT TOP (1) [TrackedExample].* FROM [TrackedExample] WHERE [TrackedExample].[id] = 1 ORDER BY TrackedExample.TrackedExampleID ASC' 

Existe-t-il un moyen d'obtenir l'élément Version # pour effectuer la requête correcte? Je me attends quelque chose comme ceci:

EXEC sp_executesql N'SELECT TOP (1) [TrackedExample].* FROM [TrackedExample] WHERE [TrackedExample].[TrackedExampleID] = 1 ORDER BY TrackedExample.TrackedExampleID ASC' 

J'utilise Rails 3.1.0, 2.6.4 paper_trail et MS SQL Server via TinyTDS et activerecord-sqlserver-adapter.

EDIT: J'ai travaillé autour du problème en ajoutant des colonnes TrackedExample.id et AnotherTrackedExample.id calculées qui se réfèrent aux valeurs de clé primaire. Ce n'est pas une bonne solution (Rails fait toujours la mauvaise requête), mais cela peut être utile aux autres.

MS SQL:

ALTER TABLE TrackedExample 
    ADD COLUMN id AS TrackedExampleID 

Répondre

0

Je ne l'ai pas essayé, mais cela pourrait fonctionner

class Version 
    belongs_to :item, :polymorphic => true, :primary_key => 'TrackedExampleID' 
    ... 
end 
+0

Cela fonctionnerait bien si toutes les classes suivies avaient la même clé primaire. Mon problème est qu'ils sont tous différents, et je ne sais pas comment le dire à la classe Version (si c'est possible). Modifié l'exemple pour clarifier la situation. –

+0

En regardant à travers les rails, je pense que votre code original devrait fonctionner tel quel. Il semble que ActiveRecord demande la clé primaire du parent polymorphe si vous n'en définissez pas. Je ne m'attendrais pas à une différence, mais essayez d'utiliser self.primary_key = au lieu de set_primary_key? –

+0

Utilisation de 'self.primary_key = 'n'a fait aucune différence, comme prévu. Mais merci de le suggérer. –

0

Après avoir écumé les documents Papertrail il ne semble pas que vous pouvez remplacer ce que la colonne item_id références (c'est-à-dire la clé primaire de la table de l'article), donc je pense que vous avez deux options principales:

1. Créez un id colonne qui n'a pas le nom de la classe en elle. Donc, id au lieu de TrackedExampleID.

Vous avez dit que vous avez déjà fait cela comme une solution rapide.

2. Saisissez et collez PaperTrail pour vous permettre de transmettre la colonne à utiliser lors de l'interrogation de item_id.

Cela peut être soit la valeur définie avec set_primary_key 'TrackedExampleID', soit une valeur définie comme has_paper_trail primary_key: 'TrakedExampleID'.

Dites-nous ce que vous finissez avec.

Questions connexes