4 votes

Rails has_many :through avec :primary_key

J'essaie de créer une relation many-to-many avec rails has_many through : mais au lieu d'utiliser la clé primaire des modèles (id), je dois créer la relation en utilisant une colonne différente. Voici mes modèles (en fait, j'utilise Rails 4) :

class Food < ActiveRecord::Base
  validates :NDB_No, uniqueness: true
  validates :NDB_No, :FdGrp_Cd, :Long_Desc, :Shrt_Desc, presence: true

  has_many :langual_factor_associations, primary_key: 'NDB_No', foreign_key: 'NDB_No'
  has_many :langual_factor_descriptions, through: :langual_factor_associations, primary_key: 'NDB_No', foreign_key: 'NDB_No'
end

class LangualFactorAssociation < ActiveRecord::Base
  validates :NDB_No, :Factor_Code, presence: true

  belongs_to :food, foreign_key: 'NDB_No'
  belongs_to :langual_factor_description, foreign_key: 'Factor_Code'
end

class LangualFactorDescription < ActiveRecord::Base
  validates :Factor_Code, uniqueness: true
  validates :Factor_Code, :Description, presence: true

  has_many :langual_factor_associations, primary_key: 'Factor_Code', foreign_key: 'Factor_Code'
  has_many :foods, through: :langual_factor_associations, primary_key: 'Factor_Code', foreign_key: 'Factor_Code'

end

L'association has_many avec LangualFactorAssociation fonctionne correctement pour Food et LangualFactorDescription. Mais l'association has_many through : entre Food et LangualFactorDescription ne fonctionne pas. Voici l'erreur que je reçois lorsque j'essaie d'accéder à Food.LangualFactorDescriptions :

Food::should create the proper relations to the LangualFactorDescription
            model#test_0002_must create the proper associations:
ActiveRecord::StatementInvalid: PG::Error: ERROR:  operator does not exist: integer = character varying
LINE 1: ...sociations" ON "langual_factor_descriptions"."id" = "langual...
                                                             ^
HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.
: SELECT  "langual_factor_descriptions".* FROM "langual_factor_descriptions" INNER JOIN "langual_factor_associations" ON "langual_factor_descriptions"."id" = "langual_factor_associations"."Factor_Code" WHERE "langual_factor_associations"."NDB_No" = $1  ORDER BY "langual_factor_descriptions"."id" ASC LIMIT 1
    test/models/food_test.rb:172:in `block (3 levels) in <top (required)>'

Je pense que le problème vient de cette partie de la requête. ON "langual_factor_descriptions". "id" = "langual_factor_associations". "Factor_Code" . Je pensais que la définition des options primary_key et/ou foreign_key réglerait le problème, mais ce n'est pas le cas. En fait, si je les supprime du modèle et que je le laisse tel qu'il est

has_many :langual_factor_descriptions, through: :langual_factor_associations

rails produit exactement la même requête, il me semble donc que la définition de ces options n'apporte rien. Est-ce que quelque chose m'échappe ? Avez-vous une idée de la façon dont je peux dire à rails de ne pas chercher le fichier langual_factor_descriptions.id mais plutôt langual_factor_descriptions.Factor_Code ?

Voici quelques-unes des ressources les plus pertinentes que j'ai lues sur ce sujet : http://guides.rubyonrails.org/association_basics.html

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

has_many :through with :primary_key on join table ne fonctionne pas (c'est à peu près le problème que j'ai mais je ne suis pas sûr que ce soit la bonne solution)

Association Rails has_many avec des clés multiples

https://www.ruby-forum.com/topic/139765

Possède de nombreuses clés primaires et étrangères alternatives

4voto

Jose Points 146

Je pense avoir réglé le problème. Voici le code :

class Food < ActiveRecord::Base
  validates :NDB_No, uniqueness: true
  validates :NDB_No, :FdGrp_Cd, :Long_Desc, :Shrt_Desc, presence: true

  has_many :langual_factor_associations, primary_key: 'NDB_No', foreign_key: 'NDB_No'
  has_many :langual_factors, through: :langual_factor_associations    
end

class LangualFactorAssociation < ActiveRecord::Base
  validates :NDB_No, :Factor_Code, presence: true

  belongs_to :food, primary_key: 'NDB_No', foreign_key: 'NDB_No'
  belongs_to :langual_factor, primary_key: 'Factor_Code', foreign_key: 'Factor_Code'
end

class LangualFactor < ActiveRecord::Base
  validates :Factor_Code, uniqueness: true
  validates :Factor_Code, :Description, presence: true

  has_many :langual_factor_associations, primary_key: 'Factor_Code', foreign_key: 'Factor_Code'
  has_many :foods, through: :langual_factor_associations    
end

Remarquez que je n'ai pas utilisé les options foreign_key ou primary_key dans les associations has_many through :, et qu'il n'est pas nécessaire d'utiliser l'option self.primary_key .

Voici également d'autres liens utiles qui m'ont aidé :

http://railsforum.com/viewtopic.php?id=36186

http://guides.rubyonrails.org/v2.3.11/active_record_querying.html

Même si la solution au problème est venue par coïncidence, je pense que ces liens fournissent des informations pertinentes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X