0

我有以下 SQL 查询:

SELECT campaigns.* , campaign_countries.points, offers.image
FROM campaigns
JOIN campaign_countries ON campaigns.id = campaign_countries.campaign_id
JOIN countries ON campaign_countries.country_id = countries.id
JOIN offers ON campaigns.offer_id = offers.id
WHERE countries.code = 'US'

这工作得很好。我想要它的rails活动记录版本,比如:

Campaign.includes(campaign_countries: :country).where(countries: {code: "US"})

上面的代码运行或多或少正确的查询(没有尝试包括优惠表),返回的问题结果是 Campaign 对象的集合,因此显然它不包括 Points

我的桌子是:

campaigns --HAS_MANY--< campaign_countries --BELONGS_TO--< countries
campaigns --BELONGS_TO--> offers

编写此 SQL 的 AR 版本有什么建议吗?我不想在我的代码中使用 SQL 语句。

4

3 回答 3

1

我知道如何在没有 SQL 的情况下工作,但肯定是穷人的解决方案:

在我的控制器中,我有:

campaigns = Campaign.includes(campaign_countries: :country).where(countries: {code: country.to_s})
render :json => campaigns.to_json(:country => country)

在活动模型中:

  def points_for_country country
    CampaignCountry.joins(:campaign, :country).where(countries: {code: country}, campaigns: {id: self.id}).first
  end

  def as_json options={}
    json = {
      id: id,
      cid: cid, 
      name: name,
      offer: offer,
      points_details: options[:country] ? points_for_country(options[:country]) : ""
    }
  end

在campaign_countries 模型中:

  def as_json options={}
    json = {
        face_value: face_value,
        actual_value: actual_value,
        points: points
    }
  end

为什么这不是好的解决方案?因为它调用了太多查询: 1. 它在执行第一次连接时调用查询以获取特定于国家/地区 2 的活动列表。对于在第一个查询中找到的每个活动,它将在campaign_countries 表上调用另一个查询以获取该活动的积分,并且国家。

这是一个糟糕的、糟糕的和糟​​糕的解决方案。有什么建议可以改进吗?

于 2013-08-23T06:11:52.067 回答
0

尝试这个:

Campaign.joins( [{ :campaign_countries =>  :countries}, :offers]).where('`countries`.`code` = ?', "US")
于 2013-08-22T19:47:38.107 回答
0

如果您有活动,您可以使用campaign.campaign_countries获取关联的活动国家并从中获取积分。

> campaign.campaign_countries.map(&:points)
=> [1,2,3,4,5]

同样,您将能够从优惠关系中获取图像。

编辑:

好吧,我想现在我知道发生了什么事。您可以使用joinswithselect从连接表中获取带有附加字段的对象。

cs = Campaign.joins(campaign_countries: :country).joins(:offers).select('campaigns.*, campaign_countries.points, offers.image').where(countries: {code: "US"})

Campaign您可以通过对象上的名称引用其他字段

cs.first.points
cs.first.image

但可以肯定的是,附加列名不会与某些主表字段或对象方法重叠。

编辑2:

经过更多研究后,我得出结论,我的第一个版本实际上对于这种情况是正确的。我将以我自己的控制台为例。

> u = User.includes(:orders => :cart).where(:carts => { :id => [5168, 5167] }).first
> u.orders.length # no query is performed
=> 2
> u.orders.count # count query is performed
=> 5

因此,当您includes在国家/地区使用条件时,campaign_countries仅存储campaign_countries满足您条件的 in。

于 2013-08-22T19:11:03.277 回答