Ammar
Ammar

Reputation: 1091

Refactor and Improve Query in Rails

Outlet.rb:

def latest_reports
  weekly_reports.limit(10)
end

Outlet_controller.rb:

@all_outlets = Outlet.includes(:weekly_reports)
@search = @all_outlets.search(params[:q])   # load all matching records
@outlets = @search.result.order("created_at DESC").page(params[:page])

outlet/index.slim:

- @outlets.each do |outlet|
  tr
    td= link_to outlet.name, outlet_path(outlet)
    th
      ul.reports
        li class="#{'done' if outlet.monitored_today}"
    th
      ul.reports
        - for report in outlet.latest_reports
          li class="#{'done' if report.quota_met}"= report.times_monitored

I'm not sure why, but this loads it up as several different queries. I'm pretty sure it's because the include in my controller isn't correct (because I'm using a method in the model).

If anyone could help me improve this, I would be extremely grateful :).

Note: I'm developing on PostgreSQL

Update:: Posted the full controller action.

Upvotes: 0

Views: 189

Answers (1)

Michael Slade
Michael Slade

Reputation: 13877

In rails 3 at least, if you use

Model1.includes :model2

then the result is one query for each model. You can access instances of the associated model from the result and no extra queries will be made.

If you really want it all in one query, you can do this:

Model1.joins(:model2).includes(model2)

This will produce a nice long JOIN query that loads all the data for both models in one go. Rails will populate the result with instances of both models already loaded.

So, you should be able to replace

@all_outlets = Outlet.includes(:weekly_reports)

with

@all_outlets = Outlet.includes(:weekly_reports).joins(:weekly_reports)

and it should combine everything into one query.

Upvotes: 2

Related Questions