首先,对不起我的英语,即使是非常基本的东西,我也很喜欢ruby on rails,所以我希望你们都能帮助我。
我有表Role和RoleUser table具有与RoleUser的has_many关系,其中role_id为外键 在表中,RoleUser包含user_id,所以我可以称之为1个角色有很多用户
我希望在每个名为total_users,
的记录中显示Role中的所有记录和附加字段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
我在控制器中有以下代码
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中的数据相结合
答案 0 :(得分:4)
如果你有这样的模型:
Class Role < ActiveRecord::Base
has_many :role_users
end
Class RoleUser < ActiveRecord::Base
belong_to :role
end
您可以使用select和join来生成摘要列,但所有Role的属性都应包含在组中。
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 console测试这些方法,这是一个很有用的工具。
<强>更新强>
根据OP的更新和评论,您似乎还有更多工作要做。
with_filtering
类方法移动到控制器 with_filtering
处理很多参数事情来获取条件,它应该在控制器而不是模型中处理。因此,我们可以将with_filtering
转移到控制器中的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
crud_index
和conditions
更新操作orders
以获取角色的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
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
和offset
的部分内容。
答案 1 :(得分:0)
根据你的解释,你可以这样做:
class Role < ActiveRecord::Base
has_many :role_users
has_many :users
def total_users
self.users.count
end
end
所以你只需要在角色对象上调用total_users
方法,它可以让你得到你想要的东西。像这样:
Role.first.total_users
# this will give you the total users for the first role found in your database.
希望有所帮助
答案 2 :(得分:0)
您可能也希望watch this Railscast:
#app/models/role.rb
Class Role < ActiveRecord::Base
has_many :role_users
has_many :users, -> { select "users.*", "role_users.*", "count(role_users.user_id) as total_users" }, through: :role_users
end
这将允许您致电:
@roles = Role.find params[:id]
@roles.users.each do |role|
role.total_users
end
您可以通过我前一段时间写的问题 - Using Delegate With has_many In Rails?
了解更多相关信息-
这是我了解Alias columns的地方,Ryan Bates用它来count
某些值: