ruby-on-rails - 虚拟列计数记录

标签 ruby-on-rails

首先,对不起我的英语,我对 Ruby on Rails 完全陌生,即使是非常基本的事情,所以我希望你们都能帮助我。

我有表 Role 和 RoleUser 表 Role 与 RoleUser 有 has_many 关系,以 role_id 作为外键 在表 RoleUser 中包含 user_id,所以我可以称其为 1 个角色有多个用户

我想要的是显示角色中的所有记录,并在每个记录中添加名为total_users的字段,

total_users中每条记录都有role_id,并统计每个角色的user_id,并将其放入total_users中,

我知道这必须使用连接表,但在rails中我对此一无所知,你们能给我一个简单的例子如何做到这一点吗?

还有一个,与上面的情况相同,我可以做例如Role.all,然后将total_users包含在其中而不将其添加到数据库中吗?那是使用虚拟列吗? 任何人都有一个很好的链接来源可以了解这一点

我在模型中有以下代码

def with_filtering(params, holding_company_id)
  order = []
  if params[:sort].present?
    JSON.parse(params[:sort]).each do |data|
      order << "#{data['property']} #{data['direction']}"
    end
  end
  order = 'id ASC' if order.blank?

  if self.column_names.include? "holding_company_id"
    string_conditions = ["holding_company_id = :holding_company_id"]
    placeholder_conditions = { holding_company_id: holding_company_id.id }
  else
    string_conditions = []
    placeholder_conditions = {}
  end

  if params[:filter].present?
    JSON.parse(params[:filter]).each do |filter|
      if filter['operation'] == 'between'
        string_conditions << "#{filter['property']} >= :start_#{filter['property']} AND #{filter['property']} <= :end_#{filter['property']}"
        placeholder_conditions["start_#{filter['property']}".to_sym] = filter['value1']
        placeholder_conditions["end_#{filter['property']}".to_sym] = filter['value2']
      elsif filter['operation'] == 'like'
        string_conditions << "#{filter['property']} ilike :#{filter['property']}"
        placeholder_conditions["#{filter['property']}".to_sym] = "%#{filter['value1']}%"
      else
        string_conditions << "#{filter['property']} = :#{filter['property']}"
        placeholder_conditions["#{filter['property']}".to_sym] = filter['value1']
      end
    end
  end

  conditions = [string_conditions.join(' AND '), placeholder_conditions]

  total_count = where(conditions).count

  if params[:limit].blank? && params[:offset].blank?
    data = where(conditions).order(order)
  else
    data = where(conditions).limit(params[:limit].to_i).offset(params[:offset].to_i).order(order)
  end

  return data, total_count.to_s
end

我在 Controller 中有以下代码

def crud_index(model)
  data, total = Role.with_filtering(params, current_holding_company)
  respond_to do |format|
    format.json { render json: { data: data, total_count: total }.to_json, status: 200 }
  end
end

我唯一的目的是添加名为total_users的虚拟字段,但我想将其添加到模型中并将其与方法with_filtering中的数据结合起来

最佳答案

如果您有这样的模型:

Class Role < ActiveRecord::Base
  has_many :role_users
end

Class RoleUser < ActiveRecord::Base
  belong_to :role
end

您可以使用选择和联接来生成摘要列,但所有角色的属性都应包含在组中。

roles = Role.select("roles.*, count(role_users.id) as total_users")
            .joins(:role_users)
            .group("roles.id")

在Rails控制台中输入这些脚本,Rails将生成如下sql:

SELECT roles.id, count(role_users.id) as total_users
FROM roles
INNER JOIN role_users
ON  roles.id = role_users.role_id
GROUP BY roles.id

然后您可以使用roles.to_json查看结果。每个角色成员都可以访问摘要列total_users

还有很多其他方式可以满足您的要求。如this 。有一个引用counter cache .

我的建议是搜索后,你可以通过rails控制台测试这些方法,这是一个有用的工具。

更新

根据OP的更新和评论,看来你还有更多的工作要做。

第1步:将with_filtering类方法移动到 Controller

with_filtering 处理很多参数来获取条件,它应该在 Controller 而不是模型中处理。因此,我们可以将 with_filtering 传输到 Controller 中的 conditionsorders 中。

class RolesController < ApplicationController

  def conditions(params, holding_company_id)
    if self.column_names.include? "holding_company_id"
      string_conditions = ["holding_company_id = :holding_company_id"]
      placeholder_conditions = { holding_company_id: holding_company_id.id }
    else
      string_conditions = []
      placeholder_conditions = {}
    end

    if params[:filter].present?
      JSON.parse(params[:filter]).each do |filter|
        if filter['operation'] == 'between'
          string_conditions << "#{filter['property']} >= :start_#{filter['property']} AND #{filter['property']} <= :end_#{filter['property']}"
          placeholder_conditions["start_#{filter['property']}".to_sym] = filter['value1']
          placeholder_conditions["end_#{filter['property']}".to_sym] = filter['value2']
        elsif filter['operation'] == 'like'
          string_conditions << "#{filter['property']} ilike :#{filter['property']}"
          placeholder_conditions["#{filter['property']}".to_sym] = "%#{filter['value1']}%"
        else
          string_conditions << "#{filter['property']} = :#{filter['property']}"
          placeholder_conditions["#{filter['property']}".to_sym] = filter['value1']
        end
      end
    end

    return [string_conditions.join(' AND '), placeholder_conditions]
  end

  def orders(params)
    ord = []
    if params[:sort].present?
      JSON.parse(params[:sort]).each do |data|
        ord << "#{data['property']} #{data['direction']}"
      end
    end
    ord = 'id ASC' if ord.blank?    
    return ord
  end
end

第2步:使用条件订单更新操作crud_index以获取角色的total_count。

class AnswersController < ApplicationController
  def crud_index(model)
    total = Role.where(conditions(params, current_holding_company)).count

    if params[:limit].blank? && params[:offset].blank?
      data = Role.where(conditions(params, current_holding_company)).order(orders(params))
    else
      data = Role.where(conditions(params, current_holding_company)).limit(params[:limit].to_i).offset(params[:offset].to_i).order(orders(params))
    end
    respond_to do |format|
      format.json { render json: { data: data, total_count: total }.to_json, status: 200 }
    end
  end
end

第3步:更新操作crud_index以获取每个角色的total_users。

确保前两个步骤通过测试。

class AnswersController < ApplicationController
  def crud_index(model)
    total = Role.where(conditions(params, current_holding_company)).count

    if params[:limit].blank? && params[:offset].blank?
      data = 
        Role.select(Role.column_names.map{|x| "Roles.#{x}"}.join(",") + " ,count(role_users.id) as total_users")
            .joins(:role_users)
            .group(Role.column_names.map{|x| "Roles.#{x}"}.join(","))
            .where(conditions(params, current_holding_company))
            .order(orders(params))
    else
      data =
        Role.select(Role.column_names.map{|x| "Roles.#{x}"}.join(",") + " ,count(role_users.id) as total_users")
            .joins(:role_users)
            .group(Role.column_names.map{|x| "Roles.#{x}"}.join(","))
            .where(conditions(params, current_holding_company))
            .order(orders(params))
            .limit(params[:limit].to_i)
            .offset(params[:offset].to_i).order(orders(params))
    end
    respond_to do |format|
      format.json { render json: { data: data, total_count: total }.to_json, status: 200 }
    end
  end
end

注意:第3步可能需要您修改conditionsorders方法来生成带有table_name前缀的column_name,以避免列名不明确的错误

如果您可以完成这些步骤,我建议您可以尝试 will_paginate 来简化代码中有关 total_countlimit偏移

关于ruby-on-rails - 虚拟列计数记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25480286/

相关文章:

ruby-on-rails - 随机搜索结果

javascript - 如何在 title 属性内的 span 元素上使用 "display: none;"?

ruby-on-rails - 如何使用 Rspec 测试wash_out Controller

mysql - 加密整个 Rails 数据库

ruby-on-rails - rake 错误找不到 rake 文件

ruby-on-rails - 如果请求包含查询字符串,则路由到单独的操作

ruby-on-rails - 主要 :Object (NameError) 的未定义局部变量或方法 `user'

ruby-on-rails - rails 3 : Loading a form Partial into an edit view of another model/controller

ruby-on-rails - 如何正确使用belongs_to和has_many?

ruby-on-rails - Rails 5 失败测试 ActiveRecord::AssociationTypeMismatch