Rails使用has_many :through with :primary_key

4

我正在尝试使用Rails的has_many through:创建多对多关系,但是我需要使用不同的列创建关系,而不是使用模型的主键(id)。

这是我的模型(顺便说一句,我正在使用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

对于Food和LangualFactorDescription,has_many与LangualFactorAssociation的关联正常工作。但是Food和LangualFactorDescription之间的has_many through:关联不起作用。当我尝试访问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)>'

我认为问题出在查询语句的这一部分 ON "langual_factor_descriptions"."id" = "langual_factor_associations"."Factor_Code"。 我曾以为设置primary_key和/或foreign_key选项可以解决这个问题,但实际上并没有。事实上,如果我从模型中删除它们,只剩下如下代码。
has_many :langual_factor_descriptions, through: :langual_factor_associations

Rails生成完全相同的查询,所以我觉得设置这些选项没有任何作用。我错过了什么吗?您有任何想法,可以告诉Rails不要查找langual_factor_descriptions.id而是langual_factor_descriptions.Factor_Code吗?

以下是我阅读过的与此主题最相关的资源之一: http://guides.rubyonrails.org/association_basics.html

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

has_many :through在联接表上使用主键无法正常工作(这基本上是我遇到的问题,但我不确定这是否是正确的解决方案)

Rails具有多个键的has_many关联

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

拥有多个“通过”关系的替代主键和外键


1
我不确定,你可以在模型LangualFactorDescription中尝试self.primary_key = 'Factor_Code'。 - yxf
好的!成功了。但我有一个问题:即使在数据库中主键仍为id,将该字段定义为模型中的主键是否可以? - Jose
我认为这是可以的,primary_key 告诉 ActiveRecord 哪个字段将用于连接另一个表。 - yxf
我明白了,如果我需要使用不同的字段与另一个模型建立另一个 has_many through: 关系,该怎么办? - Jose
1个回答

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_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

请注意,在 has_many through: 关联中,我没有使用 foreign_key 或 primary_key 选项,并且不需要 self.primary_key

此外,以下是其他对我有帮助的有用链接:

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

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

尽管问题的解决是巧合,但我认为这些链接提供了相关信息。

4
就命名和最佳实践而言,这是我见过的最糟糕的例子之一。我至少需要3分钟才能完全理解你使用的数字以及各个部分的含义。请考虑更新您的示例,使用正确的命名方式,并可能提供一个模式表格示例。 - bastianwegge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接