我有一个国家模型和一个旅行笔记模型。一个国家有许多旅行记录,旅行记录属于一个国家。
class TravelNote < ActiveRecord::Base
default_scope { order(created_at: :desc) }
belongs_to :country
has_many :chapters
before_destroy { draft? }
validate :validates_uniqueness_of_draft, on: :create
enum status: { draft: 0, published: 1, archived: 2 }
enum advice_against: { no: 0, general: 1, tourists: 2 }
scope :country, ->(country_id) { where(country_id: country_id) }
# further methods omitted...
end
class Country < ActiveRecord::Base
default_scope { order(:iso_code) }
has_many :travel_notes
end
app / controllers / countries_controller.rb中的:
class CountriesController < ApplicationController
def index
@countries = Country.includes(:travel_notes)
end
# rest of the class omitted...
end
在app / views / countries / index.html.haml中:
@countries.each do |country|
%tr
%td= link_to country.name_de, country_travel_notes_path(country)
%td= TravelNote.published.country(country.id).first.try :published_at
由于性能原因,我想删除TravelNote.published.country(country.id).first.try:published_at,以便不再有数百个数据库查询,而只是一个等效的SQL查询数组:
select * from countries
left join travel_notes
on countries.id=travel_notes.country_id
我怎样才能实现它?
答案 0 :(得分:1)
您可以编写自定义范围,仅包含已发布的笔记。
类似
scope :include_published, -> { proc do |_|
joins("LEFT OUTER JOIN (
SELECT b.*
FROM travel_notes b
WHERE published = 1
GROUP BY b.country_id
) notes_select ON notes_select.country_id = countries.id"
).select("countries.*").select("#{insert what attributes you want to include }")
end.call(self, counted_model) }
您必须在第二个选择子句中包含所需的属性,然后它们将作为具有相同名称的方法包含在国家/地区活动记录结果中。
SQL查询可以写得更漂亮,我只是把东西放在一起......
我在项目中使用了类似的技术,但是为了包含相关对象的计数。
答案 1 :(得分:1)
显然,您正试图加载与该国家相关的“travel_notes”:
Country.includes(:travel_notes).where(travel_notes: { status: 1} )
所以你的代码将是:
class CountriesController < ApplicationController def index @countries = Country.includes(:travel_notes).where(travel_notes: { status: 1} ) end # rest of the class omitted... end
@countries.each do |country|
%tr
%td= link_to country.name_de, country_travel_notes_path(country)
%td= country.travel_notes.first.published_at