我有以下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语句。
答案 0 :(得分: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表上再调用一次查询,以获取该广告系列和国家/地区的点数。
这是糟糕的,坏的和坏的解决方案。有什么建议可以改善这个吗?
答案 1 :(得分:0)
如果您有广告系列,则可以使用campaign.campaign_countries
获取关联的广告系列国家,并从中获取积分。
> campaign.campaign_countries.map(&:points)
=> [1,2,3,4,5]
同样,您将能够从优惠关系中获取图像。
编辑:
好的,我想现在我知道发生了什么事。您可以将joins
与select
一起使用,以获取包含连接表中附加字段的对象。
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
。
答案 2 :(得分:0)
试试这个:
Campaign.joins( [{ :campaign_countries => :countries}, :offers]).where('`countries`.`code` = ?', "US")