从另一张桌子

时间:2018-05-07 20:42:44

标签: ruby-on-rails postgresql activerecord

我有一个多对多,HMT模型设置,我想添加一个计数值作为tab_community#index方法的一部分返回。感兴趣的表和连接表的模型如下:

class TabCommunity < ApplicationRecord
  belongs_to :ref_community_type

  has_many :tab_client_project_communities
  has_many :tab_projects, through: :tab_client_project_communities

  has_many :tab_community_accounts
  has_many :tab_accounts, through: :tab_community_accounts

  has_many :tab_client_project_communities
  has_many :ref_platforms, through: :tab_client_project_communities
end

class TabCommunityAccount < ApplicationRecord
  belongs_to :tab_community
  belongs_to :tab_account
end

#index方法目前看起来像这样:

_tab_community_ids = params[:tab_community_ids].split(',')
@tab_communities = TabCommunity.where(id: _tab_community_ids).includes(:ref_platforms).all.order(:updated_at).reverse_order

此查询是我想在ActiveRecord中复制的内容:

select (select count(*) from tab_community_accounts where tab_community_id = c.id) as cnt, c.* from tab_communities c

我想要的结果如下:

7318    149 sports_writers  7   2017-12-17 15:45:36.946965  2017-12-17 15:45:36.946965
0   172 random_admin    8   2018-04-16 19:21:21.844041  2018-04-16 19:21:21.844041
2731    173 random_aacc 7   2018-04-16 19:22:35.074461  2018-04-16 19:22:35.074461

(第一列为count(*) from tab_community_accounts,其余列为tab_communities。)

从我到目前为止所见,我应该使用.select().pluck(),但两者都不适合我。我试过这个:

TabCommunity.pluck("distinct tab_community_accounts.tab_account_id as cnt").where(id: _tab_community_ids).includes(:ref_platforms).all.order(:updated_at).reverse_order

这接近我需要的还是完全关闭?

1 个答案:

答案 0 :(得分:3)

你想要的是:

@tab_communities = TabCommunity
  .where(id: _tab_community_ids)
  .select('tab_communities.*, count(tab_community_accounts.id) AS cnt')
  .left_outer_joins(:tab_community_accounts)
  .includes(:ref_platforms) # consider if you actually need this
  .group(:id)
  .order(updated_at: :desc) # use an explicit order instead!
  TabCommunity Load (1.1ms)  SELECT tab_communities.*, count(tab_community_accounts.id) AS cnt FROM "tab_communities" LEFT OUTER JOIN "tab_community_accounts" ON "tab_community_accounts"."tab_community_id" = "tab_communities"."id" WHERE "tab_communities"."id" = 1 GROUP BY "tab_communities"."id" ORDER BY "tab_communities"."updated_at" DESC
=> #<ActiveRecord::Relation [#<TabCommunity id: 1, created_at: "2018-05-07 21:13:24", updated_at: "2018-05-07 21:13:24">]>

.select只是改变了查询的SELECT部分。返回的结果仍然是包含模型实例的ActiveRecord::Relation

ActiveRecord将自动为cnt创建一个属性:

irb(main):047:0> @tab_communities.map(&:cnt)
=> [1]
另一方面,

.pluck只是拉取列值,如果查询包含多个列,则返回数组或数组数组。

@tab_communities = TabCommunity
  .where(id: _tab_community_ids)
  .left_outer_joins(:tab_community_accounts)
  .includes(:ref_platforms) # consider if you actually need this
  .group(:id)
  .order(updated_at: :desc)
  .pluck('tab_communities.id, count(tab_community_accounts.id) AS cnt')
 (1.0ms)  SELECT tab_communities.id, count(tab_community_accounts.id) AS cnt FROM "tab_communities" LEFT OUTER JOIN "tab_community_accounts" ON "tab_community_accounts"."tab_community_id" = "tab_communities"."id" WHERE "tab_communities"."id" = 1 GROUP BY "tab_communities"."id" ORDER BY "tab_communities"."updated_at" DESC
=> [[1, 1]]

使用.*并不是一个好主意,因为你不知道属性在结果数组中的顺序。