【发布时间】:2017-08-10 01:32:42
【问题描述】:
我在 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#index,我如何至少从用户拥有的所有Projects 中回复所有Activities?
或者是否有一些关于如何使用我一直错过的 Rails 更好地编码的约定?
我也安装了 Pundit,但仅用于根据用户的角色授权对用户的操作,我已经看到它可用于为模型编写自定义范围,但我不知道如何正确使用它来处理任何复杂的事情比“用户组织的所有项目”查询(角色为“admin”的用户的用例)。
在开始时也尝试使用“公寓”gem,并为每个组织使用单独的模式,在这种情况下查询更简单,但我给了我奇怪的行为,比如随机无法创建关系,抱怨一些记录在创建时不存在外键。所以我不得不停止使用它。
【问题讨论】:
标签: rails-activerecord ruby-on-rails-5 active-model-serializers rails-api pundit