首先,对不起我的英语,我对 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 中的 conditions
和 orders
中。
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步可能需要您修改conditions
和orders
方法来生成带有table_name前缀的column_name,以避免列名不明确的错误
如果您可以完成这些步骤,我建议您可以尝试 will_paginate
来简化代码中有关 total_count
、limit
和偏移
。
关于ruby-on-rails - 虚拟列计数记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25480286/