【问题标题】:Multiple belongs_to to the same table多个belongs_to属于同一张表
【发布时间】:2013-02-24 20:11:59
【问题描述】:

我有两张桌子:

货币和汇率

currencies: id:int, code:string, name: string

rates: id:int, top_currency_id:int, bottom_currency_id:int, rate:float

我有两个活动记录:

class Rate < ActiveRecord::Base
  attr_accessible :bottom_currency, :rate, :top_currency, :top_currency_id

  belongs_to :top_currency, :class_name => 'Currency', :foreign_key => 'top_currency_id'
  belongs_to :bottom_currency, :class_name => 'Currency', :foreign_key => 'bottom_currency_id'
end


class Currency < ActiveRecord::Base
  attr_accessible :code, :name

  has_many :rates
end

所以问题是: 当我试图执行以下代码时: top_currency = Currency.find_by_id(1) @test = Rate.where(:top_currency=>top_currency)

我收到以下错误:

Mysql2::Error: Unknown column 'rates.top_currency' in 
'where clause': SELECT `rates`.* FROM `rates`  WHERE `rates`.`top_currency` = 1

为什么 Rails 的魔法不起作用?

非常感谢。

【问题讨论】:

  • 错误指出top_currency 不是rates 表中的列,您确定将更改迁移到您正在使用的环境中吗?
  • @JaredMcAteer 我有 top_currency_id 列,我认为 Rails 应该寻找 top_currency_id 列 insted of top_currency。

标签: ruby-on-rails ruby-on-rails-3 model-associations


【解决方案1】:

在您的两个belongs_to 方法中,将foreign_key 选项更改为primary_key,其他所有内容保持不变。

belongs_to :top_currency, :class_name => 'Currency', :primary_key => 'top_currency_id'
# ...

默认情况下,关联对象的主键是id。但是,您的货币模型具有三个主键,即预期的 id 加上两个额外的键:top_currency_id 和 bottom_currency_id。 Active Record 需要知道要查找的密钥。用primary_key 选项告诉它。

当外键不同于关联名称 (belongs_to :name) 加上“_id”时,需要使用 foreign_key 选项。由于您的外键匹配关联名称加上“_id”,因此您不需要使用foreign_key 选项。

【讨论】:

  • 不,很遗憾我只有一个主键。
【解决方案2】:

据我所知,您的代码理论上应该可以工作。但我确实认为你有点多余。

这样做就足够了:

class Rate < ActiveRecord::Base
  belongs_to :top_currency, class_name: 'Currency'
  belongs_to :bottom_currency, class_name: 'Currency'
end

Rails 会推断 top_currency 的外键是 top_currency_id,bottom_currency_id 是 bottom_currency。

【讨论】:

  • 你确定类名不应该是符号或字符串吗?
【解决方案3】:

我认为你不能这样查询关系。使用您的示例:

top_currency = Currency.find_by_id(1)
@test = Rate.where(:top_currency=>top_currency)

你必须把它改成这样:

top_currency = Currency.find_by_id(1)
@test = Rate.where(:top_currency_id => top_currency.id)

但这样做可能更容易:

top_currency = Currency.find_by_id(1)
@test = top_currency.rates

【讨论】:

  • 是的,@test = Rate.where(:top_currency_id =&gt; top_currency.id) 甚至 @test = Rate.where(:top_currency_id =&gt; top_currency) 都很好用。但我想让Rate.where(:top_currency=&gt;top_currency) 工作
  • 只是好奇,当您建立的关联为您提供top_currency.rates 做同样事情的方法时,您为何如此执着于拥有Rate.where(:top_currency=&gt;top_currency)?
  • @MollyStruve 实际上我需要执行以下请求:Rate.where(:top_currency=&gt;top_currency, :bottom_currency=&gt;bottom_curency)
  • 据我所知,你不能这样做。将 _id 添加到每个符号中,它就会起作用。我知道您要做什么,但是在简单的查询中是不可能的。您正在寻找一个连接,这比简单地检查相关记录的 id 要昂贵得多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多