我在API模式下使用Rails 5.0.5的API。在每个控制器请求中,我们使用Active Model Serializers以render json:
进行响应。我们使用postgresql作为数据库。
让我们假设这是我的数据库:
鉴于所有查询都需要用户登录,我才能获得current_user
对象:
我可以从HABTM关系中获取用户的所有项目,例如:
render json: current_user.projects
我想仅针对用户所属的项目查询Departments
,ActivityTypes
和Status
(不传递参数)。
(在真正的API中,有7个类似的模型属于Project
,并且至少有2个至少有几百个记录。此外,客户端需要加载其中的7个查看Project
,允许他们在同一视图中构建新的Activities
。)
从现在开始,我想出了这个来显示索引,至少来自组织用户所属的Departments
:
def index
# @departments = Department.all
@departments = Department.joins(project: 'organization').where(:project => { 'organizations' => {:id => current_user.organization.id }})
render json: @departments
end
使用数据库中的3个查询:
Started GET "/api/v1/departments" for 127.0.0.1 at 2017-08-09 19:40:57 -0400
Processing by Api::V1::DepartmentsController#index as HTML
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
Organization Load (0.4ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
Department Load (6.8ms) SELECT "departments".* FROM "departments" INNER JOIN "projects" ON "projects"."id" = "departments"."project_id" INNER JOIN "organizations" ON "organizations"."id" = "projects"."organization_id" WHERE "organizations"."id" = $1 [["id", 1]]
[active_model_serializers] Project Load (0.5ms) SELECT "projects".* FROM "projects" WHERE "projects"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
[active_model_serializers] CACHE (0.0ms) SELECT "projects".* FROM "projects" WHERE "projects"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
[active_model_serializers] Project Load (0.3ms) SELECT "projects".* FROM "projects" WHERE "projects"."id" = $1 LIMIT $2 [["id", 3], ["LIMIT", 1]]
[active_model_serializers] CACHE (0.0ms) SELECT "projects".* FROM "projects" WHERE "projects"."id" = $1 LIMIT $2 [["id", 3], ["LIMIT", 1]]
[active_model_serializers] Rendered ActiveModel::Serializer::CollectionSerializer with ActiveModelSerializers::Adapter::Attributes (21.79ms)
Completed 200 OK in 110ms (Views: 33.5ms | ActiveRecord: 20.4ms)
这是一方面的。
此外,相当于我的真实API中的Activities
,实际上每个组织有数千条记录,
如果我可以传递project_id
作为参数,我可以获得更窄的子集,但如果没有传递参数,我需要使用默认查询进行响应。
事实上,所有这些查询的响应时间都已在生产环境中达到几秒的数量级。
有没有办法让这3个查询只有一个?
有没有办法为这些模型的所有#all查询设置此默认设置?
如果没有'project_id'传递给Activities
,我如何至少回复用户所有Projects
的所有Activities#index
?
或者是否有一些关于如何使用我错过的Rails更好地编码的惯例?
我也安装了Pundit,但仅用于根据用户的角色授权用户操作,我看到它可以用来为模型编写自定义范围,但我还没有得到如何正确使用它来处理任何复杂的事情比“用户组织的所有项目”查询(用户角色为“admin”的用例)。
在开始时也尝试使用“Apartment”gem,并为每个组织单独设置模式,在这种情况下查询更简单,但我给了我奇怪的行为,如随机无法创建关系抱怨一些记录在创建时不存在外键。所以我不得不停止使用它。
答案 0 :(得分:0)
我可能在这里遗漏了一些东西,但在@project
上定义实例方法有什么问题:
def project_data
{'project' => self,
'departments' => departments,
'activity_types' => activity_types,
'status' => status
}
end
然后在你的控制器中:
render json: current_user.projects.map{|x| x.project_data}