Let's create for the catalogs and items tables models 1: N. Moreover, in the Catalog model, we will additionally create the total method, which will refer to the calculated total column in the resulting query (in fact there is no such column in the catalogs table).
class Item < ActiveRecord::Base belongs_to :catalog end class Catalog < ActiveRecord::Base has_many :items def total self[:total] end end
Up to Rails 5
Prior to Rails 5, only the joins method is available, in which the LEFT JOIN and ON constructs should be explicitly specified. Moreover, using the assignment of aliases AS will not work - the table names will have to be written explicitly. In addition, it is necessary to explicitly register all the columns of the catalogs table, adding them with the expression COUNT(i.id) AS total .
catalogs = Catalog .joins('LEFT JOIN items ON catalogs.id = items.catalog_id') .select('catalogs.id AS id, catalogs.name AS name, COUNT(items.id) AS total') .group('catalogs.id') catalogs.collect{|x| [x.id, x.name, x.total] } => [[2, "Каталог 2", 2], [1, "Каталог 1", 0], [3, "Каталог 3", 1]]
Rails 5
Beginning with Rails 5, a separate left_joins method is available in ActiveRecord. Otherwise, the order of forming such requests and getting results remains the same.
catalogs = Catalog .left_joins(:items) .select('catalogs.id AS id, catalogs.name AS name, COUNT(items.id) AS total') .group('catalogs.id') catalogs.collect{|x| [x.id, x.name, x.total] } => [[2, "Каталог 2", 2], [1, "Каталог 1", 0], [3, "Каталог 3", 1]]